Commit Graph

6 Commits

Author SHA1 Message Date
João Moura
9e9a8577be feat(events): report project creation with the id minted for it (#7074)
* feat(telemetry): report project creation with the id minted for it

Acquisition was only observable from a project's first run. That misses every
project created and never run, and dates the rest to the wrong day.

All three scaffolding paths already mint a project_id into the new
pyproject.toml. None of them reported it, and two of them - create_crew and
create_json_crew, which is the default `crewai create crew` path - emitted no
telemetry at all.

`Project Created` carries the kind (crew, json_crew, flow) and the id that was
just minted, and is emitted after the mint so it can carry it.

The attribute is `created_project_id`, not `project_id`, because those are two
different things. CommonAttributesSpanProcessor stamps `project_id` on every
span from get_project_id(), which reads the current working directory and is
cached for the life of the process - during `crewai create` that describes the
directory the command was run from, not the project being created. Reusing the
name would have given one column two meanings depending on span type.

Nothing is emitted for `create_crew(parent_folder=...)`: that adds a crew to a
project which already exists, mints no id, and is not an acquisition.

The existing `Flow Creation` span is left exactly as it is. Note for whoever
reads it: it is emitted from two places with two different meanings - CLI
scaffolding (create_flow.py) and runtime flow construction (event_listener.py on
FlowCreatedEvent) - so it cannot separate acquisition from usage. Not changed
here because it is a live series and renaming it would break continuity.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RfV2uMqWRcdfufMvtdCVoN

* test(telemetry): stop the creation-span tests exporting to the real collector

The recorded_spans fixture has to enable telemetry for its assertions to mean
anything - a disabled Telemetry never builds self.provider, so every assertion
would pass vacuously against a non-recording span. But enabling it is exactly
what makes __init__ wire a BatchSpanProcessor around the real
SafeOTLPSpanExporter, pointed at the production collector.

Measured, with a spy on both SafeOTLPSpanExporter classes reporting at
interpreter exit: before this change the file made 3 real export calls, handed 3
synthetic Project Created spans with invented created_project_id values to the
production exporter, and completed 3 connects to the collector. After: 0, 0, 0.

Sampling at pytest_sessionfinish reports 0 either way and is how this was missed
- BatchSpanProcessor flushes on a background timer, and with no
provider.shutdown() the flush lands in the atexit handler, which runs after
sessionfinish.

--block-network does not prevent it: it is function-scoped and only swaps
socket.connect, which a background batch thread outlives.

Follows telemetry_with_exporter in tests/telemetry/test_tracer_isolation.py:
_NullExporter swapped in before construction, _register_shutdown_handlers
suppressed so no atexit hook is left behind, and provider.shutdown() in finally.
Patch target is crewai_core because that is where this Telemetry comes from.

Also disambiguates the docs rows: the minted ID belongs to the new project, not
to the directory the command ran in, and the two can differ. Reworded in all four
languages rather than renaming the token to created_project_id - this table
documents data, never span-attribute keys (kind and crewai_version on the same
row are unnamed), and `project_id` is already the page's name for the
pyproject.toml key.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RfV2uMqWRcdfufMvtdCVoN

* docs(ar): use tanwin fath on the letter, not on the alif

مشروعًا / جديدًا rather than مشروعاً / جديداً, in the row added by this PR.

Both forms appear in docs/edge/ar (3 each), so this is not a house convention
being broken either way; the corrected form is the more standard one and the text
is mine.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RfV2uMqWRcdfufMvtdCVoN

* docs: stop the creation row implying the span's project_id holds the minted value

CodeRabbit re-raised this as Major after I rejected the first version, and it was
right to. My rejection argued the page never names wire keys, so introducing
created_project_id would be its only one. That part still holds -- grep finds no
attribute key anywhere in the four files. But it was the wrong conclusion: the row
still used the token `project_id` for a value the span does NOT carry under that
key, while the same span's real project_id holds the cwd-derived value. The row
also already exposes literal wire values (`crew`, `json_crew`, `flow` are the
actual kind values), so "this page has no wire detail" was overstated.

Dropping the token resolves the ambiguity without adding the page's only key
name: the row now says "the project ID minted for that new project", and names
`project_id` only to say the minted value is recorded separately from it.

All four languages. No docs/v*/ touched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RfV2uMqWRcdfufMvtdCVoN

* docs: use an em dash in the creation row, matching the rest of the page

The two ASCII `--` occurrences in these files were both mine, introduced by this
PR: the page otherwise uses em dashes throughout (en 4, ar 4, ko 2, pt-BR 4).

CodeRabbit flagged pt-BR; the same slip was in en, so both are fixed. Now zero
ASCII `--` across all four language files.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RfV2uMqWRcdfufMvtdCVoN

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-08-23 15:59:56 -03:00
João Moura
b10c4ffcdc feat: add project_id to link OSS usage to an enterprise account (#6791)
Some checks failed
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Vulnerability Scan / pip-audit (push) Has been cancelled
Build uv cache / build-cache (3.10) (push) Has been cancelled
Build uv cache / build-cache (3.11) (push) Has been cancelled
Build uv cache / build-cache (3.12) (push) Has been cancelled
Build uv cache / build-cache (3.13) (push) Has been cancelled
Nightly Canary Release / Check for new commits (push) Has been cancelled
Nightly Canary Release / Build nightly packages (push) Has been cancelled
Nightly Canary Release / Publish nightly to PyPI (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
* feat: add project_id to link OSS usage to an enterprise account

Adds a stable per-project identifier so a project's OSS traces and runs can
be attributed to an account after signup. There was no such identifier
before: [tool.crewai] held only `type`, the deploy UUID was printed to the
console but never persisted, Settings.org_uuid is global rather than
per-project, and trace batches carried only crew_fingerprint/crew_name.

The id lives in the project's pyproject.toml, so it is committed with the
repository and stays stable across machines, teammates, CI, and containers -
unlike a machine- or user-derived identifier, which is unstable in exactly
the containerized production environments that matter most.

crewai-core:
- get_project_id(): read-only lookup of [tool.crewai].project_id. Safe for
  library code; never creates or modifies anything.
- get_or_create_project_id(): mints a uuid4 and persists it, returning
  (id, created) so callers can tell the user. Best-effort - returns
  (None, False) for a missing, malformed, or read-only pyproject.toml rather
  than raising.
- Insertion edits the raw TOML text instead of round-tripping through a
  writer, so comments, key order, and formatting elsewhere survive. The key
  is placed at the end of the [tool.crewai] table, before the next table
  header, so it cannot land in a neighbouring section.
- LoginPayload and TraceExecutionContext gain optional project_id.

Sent on two paths:
- Traces: project_id is added to execution_context, which is sent on both
  the ephemeral and authenticated paths, so a project's traces remain
  attributable before and after the user creates an account.
- Login: `crewai login` already sends the pseudonymous user_identifier on an
  authenticated request; adding project_id means one request carries account
  + user + project, which is the link itself.

Minting is restricted to CLI commands the user explicitly invoked - `crewai
create` for new projects and `crewai run` to backfill existing ones - and is
announced when it happens. Library code only ever reads. Silently rewriting
a user's pyproject.toml during Crew.kickoff() would be surprising.

Privacy: project_id is a random uuid4 in a file the user commits. It is
visible in a diff, contains nothing personal, and identifies a project
rather than a person - so this needs none of the notice changes that
attaching a user identifier to all telemetry would require.

Tests: 18 new tests covering minting, stability, table placement, comment
and formatting preservation, five pyproject layouts, the neighbouring-table
regression, and graceful handling of missing/malformed/read-only files.
Verified end-to-end that both create paths mint distinct ids, that the trace
payload carries project_id on both the ephemeral and authenticated paths,
and that the login payload carries user_identifier and project_id together.

Follow-ups, deliberately not included: adding project_id to telemetry spans,
and backend persistence of the (account, user_identifier, project_id) triple.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNumDnNbiyw3pv1WakAe6t

* refactor: drop the console announcement when minting project_id

Minting now happens silently. With no message to print, the (id, created)
tuple had no consumer, so simplify the API rather than keep the flag around
for a hypothetical caller:

- get_or_create_project_id() returns `str | None` instead of
  `tuple[str | None, bool]`.
- Remove crewai_cli.utils.ensure_project_id, which existed only to print the
  message and discard the flag. The four call sites (crewai create crew,
  crewai create flow, crewai run, and tool-repository login) now call
  get_or_create_project_id directly.
- Update tests for the simplified signature; still 18 tests covering minting,
  stability, table placement, formatting preservation, five pyproject
  layouts, and missing/malformed/read-only handling.

Behaviour is otherwise unchanged: minting stays restricted to CLI commands
the user invoked, library code still only reads via get_project_id, and a
missing or read-only pyproject.toml still returns None rather than raising.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNumDnNbiyw3pv1WakAe6t

* fix: harden project_id minting against TOML corruption; address review

Several reviewers found ways the raw-text edit could produce invalid TOML.
Each is now fixed and covered by a test that fails without the fix.

Duplicate project_id key (Cursor bugbot, Copilot x2):
- get_project_id() reports a blank or non-string value as "absent", so a file
  containing `project_id = ""` took the insert path and gained a second
  project_id line - a duplicate key, and therefore invalid TOML that no
  tomli-based tool could read afterwards.
- _insert_project_id is now _set_project_id: it replaces an existing
  assignment inside [tool.crewai] instead of appending unconditionally.

Table header with a trailing comment (CodeRabbit major, Cursor bugbot):
- `[tool.crewai]  # config` is valid TOML but failed exact string equality,
  so the fallback appended a second [tool.crewai] header - a redefined table,
  also invalid TOML, and silent because get_project_id swallows the resulting
  decode error.
- Added _is_table_header(), which tolerates a trailing comment and does not
  match similar names such as [tool.crewai-extra].

Writing into malformed TOML (Cursor bugbot, Copilot):
- get_or_create_project_id relied on get_project_id, which cannot distinguish
  "no id" from "unparsable file", so it appended to files it could not parse.
- The locked path now parses explicitly and bails on a decode error, and
  re-parses the updated content before writing, so this feature can never be
  the reason a project's pyproject.toml stops parsing.

Concurrency and atomicity (CodeRabbit major):
- Two CLI processes could both see no id, mint different uuids, and clobber
  each other, leaving a caller holding an id that is not on disk. Minting now
  takes the existing crewai_core cross-process lock, re-reads under it, and
  returns the id that persists.
- Writes go through a temp file in the same directory plus os.replace, so an
  interruption cannot truncate pyproject.toml. File mode is copied across, and
  the temp file is removed on failure.
- os.replace only needs a writable directory, which would have let an atomic
  write silently overwrite a file the user marked read-only; writability is
  now checked explicitly so that case still returns None.

Line endings (CodeRabbit):
- Path.read_text/write_text normalized CRLF to LF, so minting would rewrite a
  CRLF-committed file entirely. Read and write now use newline="" and the
  inserted line ending is derived from the existing content.

Default create path skipped minting (Cursor bugbot):
- `crewai create crew` defaults to create_json_crew; only the --classic and
  flow paths minted, so most new projects had no id until a later command.
  Wired into create_json_crew as well. Verified all three paths now mint
  distinct ids.

Do not mint during login (CodeRabbit major):
- ToolCommand.login ran get_or_create_project_id, which is outside the
  sanctioned minting commands and is invoked by `crewai tools create` from a
  freshly scaffolded directory before the project is persisted. It now uses
  the read-only get_project_id. Verified login leaves pyproject.toml
  untouched.

Not applied: Copilot asked for a console message when an id is written, in
create_crew and create_flow. Minting was made deliberately silent in the
previous commit, so the (id, created) tuple and the announcement are both
gone by design.

Tests: 32 in test_project_id.py, up from 18. New cases cover blank and
non-string existing ids, three commented-header forms, similar table names,
malformed input, CRLF and LF preservation, concurrent minting convergence,
file-mode preservation, and temp-file cleanup. Confirmed the header and
duplicate-key tests fail when the fixes are reverted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNumDnNbiyw3pv1WakAe6t

* fix: never create [tool.crewai], treat whitespace ids as absent, harden test

`crewai run` could rewrite unrelated projects (Cursor bugbot, high):
- get_or_create_project_id ran before the cwd was established as a CrewAI
  project, and _set_project_id appended a [tool.crewai] table when none
  existed. Any directory with a pyproject.toml could therefore gain one -
  including on `crewai run --definition`, which may otherwise succeed.
- _set_project_id no longer creates the table; it returns None when
  [tool.crewai] is absent, so a key is only ever added to a table the project
  already declares. The templates all ship the table, so no create path needs
  the old fallback.
- The minting call in run_crew moved after the --definition early return, so
  an explicit-flow run does not touch the cwd at all.
- Presence is checked, not truthiness: an empty [tool.crewai] is still a
  CrewAI marker, and get_crewai_project_config returns {} both for that and
  for an absent table.
- Verified an unrelated project's pyproject.toml is byte-identical after a
  mint attempt.

Whitespace-only project_id accepted as valid (CodeRabbit):
- `project_id = "   "` is truthy, so it was returned as an identity and would
  have propagated into login payloads and tracing context. It also meant the
  '"   "' parameter of the replacement test asserted nothing.
- Added _usable_project_id, which strips before deciding, used by both
  get_project_id and the locked mint path.

Concurrency test could hang CI (CodeRabbit, major):
- Neither the barrier nor the joins had timeouts, so a thread dying early or
  blocking on the lock would hang the job rather than fail it. The result
  count was also unchecked, so a dead thread still passed.
- Added timeouts, an explicit liveness assertion, a result-count assertion, a
  lock around the shared result list, and corrected the docstring: this covers
  the read-modify-write race with threads, not the cross-process backend.

Tests: 35, up from 32. New coverage for the absent-table refusal and three
whitespace forms; the blank-id replacement case now asserts a real uuid
replaced the blank value.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNumDnNbiyw3pv1WakAe6t

* chore(deps): force gitpython 3.1.57+ for GHSA-p538-c434-8v24 and GHSA-3f7w-8rr8-f37f

Unrelated to project_id; bundled here only because it blocks this PR's
vulnerability scan. Two advisories were published for gitpython 3.1.55 after
main last passed the scan:

- GHSA-p538-c434-8v24: arbitrary file truncation via `git rev-list --output`
  argument injection. Fixed in 3.1.56.
- GHSA-3f7w-8rr8-f37f: unguarded git option forwarding in
  IndexFile.checkout() and TagReference. Fixed in 3.1.57.

- Bump the override floor to gitpython>=3.1.57 and declare the same floor in
  crewai-tools, so consumers installing the published package are covered and
  not only this repo's lock.
- 3.1.57 was published 2026-07-26, past gitpython's exclude-newer-package
  cutoff of 2026-07-24, so that cutoff moves to 2026-07-27. Without it the
  floor is unresolvable.

pip-audit against the updated lock reports no known vulnerabilities.
Verified gitpython 3.1.57 resolves and that crewai_tools and crewai_cli.git
still import.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNumDnNbiyw3pv1WakAe6t

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 15:25:06 -07:00
Vinicius Brasil
e1ddb32e56 Initialize Git repositories for generated projects (#6364)
Some checks failed
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Check Documentation Broken Links / Check broken links (push) Has been cancelled
Vulnerability Scan / pip-audit (push) Has been cancelled
Nightly Canary Release / Check for new commits (push) Has been cancelled
Nightly Canary Release / Build nightly packages (push) Has been cancelled
Nightly Canary Release / Publish nightly to PyPI (push) Has been cancelled
2026-06-26 16:29:49 -07:00
João Moura
ebbc0998ef Implement DMN mode support in crew creation and execution (#6194)
* Implement DMN mode support in crew creation and execution

- Added `is_dmn_mode_enabled` utility to check for enterprise non-interactive mode based on the `CREWAI_DMN` environment variable.
- Updated `create` function in `cli.py` to enforce required parameters when DMN mode is active, raising appropriate usage errors.
- Enhanced `create_crew` and `create_json_crew` functions to skip provider prompts and handle folder existence checks in DMN mode.
- Introduced non-interactive defaults for agent and task creation in DMN mode, ensuring seamless project setup without user input.
- Modified `run_crew` to bypass TUI and handle runtime inputs directly when in DMN mode, improving execution flow for JSON-defined crews.
- Added tests to validate DMN mode behavior, ensuring correct handling of required inputs and non-interactive defaults.

* Implement DMN mode support in crew creation and execution

- Introduced `is_dmn_mode_enabled()` utility to check for non-interactive mode based on the `CREWAI_DMN` environment variable.
- Updated `create` function to enforce required parameters when DMN mode is active, raising appropriate usage errors.
- Modified `create_crew` and `create_json_crew` functions to skip provider prompts and utilize non-interactive defaults in DMN mode.
- Enhanced `run_crew` to bypass TUI and handle runtime inputs directly in DMN mode, ensuring smooth execution without user interaction.
- Added tests to validate DMN mode behavior, including requirements for type and name, and ensuring proper handling of existing folders and missing inputs.
2026-06-16 19:48:31 -03:00
Greyson LaLonde
bad64b1ee6 chore(cli): drop self-explanatory comments
Some checks failed
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Vulnerability Scan / pip-audit (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
2026-05-26 01:05:25 -07:00
Greyson LaLonde
93e786d263 refactor: extract CLI into standalone crewai-cli package 2026-05-06 20:46:46 +08:00