Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ When falling back, state which c3_* tool was attempted and why it was insufficie
9.5. **LOCAL CI** (v2.79.0+): `c3_ci(action='inspect|run|rerun|status|failures|logs|runs')` — run THIS repository's real `.github/workflows/*.yml` on this machine instead of pushing to find out. C3 reads the existing workflow files; it does NOT define a second CI config. `inspect` shows the job DAG and which jobs are runnable on this host; `run` executes in `needs` order and SKIPS (never passes) a job whose dependency failed; `failures` returns `{file,line,message}` instead of raw logs; `rerun` retries only what failed. VERDICTS: `FULL_CI_PASS` means every job ran HERE and passed — the only one that means safe to push. `PARTIAL_PASS` means something did not run (targets another OS, uses an action C3 cannot execute, or you selected a subset) and is NOT a green light. Jobs targeting another OS are refused unless `allow_foreign=true`, which labels the result cross-OS and can never yield FULL_CI_PASS. ENGINES (v2.81.0+): `native` runs jobs matching this host; `act` runs Linux jobs in a real container (real `uses:` actions included) when act+Docker are installed — `c3_ci(action='doctor')` reports what is available. A container run DOES count toward FULL_CI_PASS; a cross-OS one never does. macOS jobs cannot run locally on any engine. Jobs that look like they publish or deploy are refused unless allow_side_effects=true, and C3 never passes secrets to act. See docs/agent-ci.md.
10. **BITBUCKET** (when configured, v2.30.0+): `c3_bitbucket(action='...')` — for self-hosted enterprise Bitbucket Data Center / Server: PRs, branches, builds, repo admin. Tokens live in the OS keyring (set up via `c3 bitbucket login`, or `login --global` for a home config reusable across projects; account resolution precedence is project → home). Read actions are safe in plan mode; write actions (`merge_pr`, `create_branch`, etc.) are auto-logged to the edit ledger.
10.5. **JIRA** (when configured, v2.56.0+): `c3_jira(action='...')` — Jira Cloud + Data Center: `search` (raw JQL), `my_issues`, `get_issue`, `list_transitions`, `get_create_metadata`, `search_users`, `list_link_types`, `list_boards`, `list_sprints`, `list_worklogs` reads; `create_issue` / `update_issue` / `comment` / `transition` / `assign` / `link_issues` / `unlink_issues` / `move_to_sprint` / `move_to_backlog` / `add_worklog` / `attach_file` / `delete_issue` (permanent; refuses subtask-bearing issues unless delete_subtasks=true) mutations auto-logged to the edit ledger (identifiers only, never bodies). createmeta reflects the issue type's field configuration, NOT the create screen — if create_issue rejects a listed field ('not on the appropriate screen'), create without it, then set it via `update_issue`. Epic membership: pass `parent=<EPIC-KEY>` to create_issue/update_issue ('none' clears) — C3 maps it per deployment (Cloud `parent` field vs Data Center Epic Link customfield); `link_issues(issue, link_type, target)` creates typed links reading '<issue> <link_type> <target>' (types via `list_link_types`). Sprints: `list_boards` → `list_sprints(board_id)` → `move_to_sprint(issue, sprint_id)`; `attach_file(issue, file_path)` uploads a local file as evidence. Tokens in the OS keyring (`c3 jira login`, or `login --global` for cross-project reuse; the jira config section resolves project → home wholesale from one file — never field-merged). Read actions are safe in plan mode.
10.6. **CREDENTIALS** (v2.58.0+): `c3_credentials(action='...')` — named secret vault (global ~/.c3 + per-project .c3; project shadows global). `list`/`describe`/`check` return names + metadata, never values. To USE a secret do NOT reveal it — pass `env_creds='NAME1,NAME2'` to c3_shell or write `{{cred:NAME}}` inside cmd; C3 decodes at the subprocess boundary so values never enter context, and echoed values are auto-redacted to `[cred:NAME]`. `reveal` works only on entries the user marked `agent_readable` (that flag cannot be raised on an existing entry by the agent). `set`/`delete` allowed; all mutations + reveals ledger-logged by name. `import_env` (v2.93.0+) bulk-imports a .env WITHOUT you seeing a value - the server reads the file, you get names/lengths/fingerprints/reasons; `**/.env*` stays a built-in deny for your own reads. It DEFAULTS TO dry_run=true (call it bare to preview, re-run dry_run=false once the user has seen the list), is project-scope only, refuses overwrite, and refuses a path outside the project. A dry run also DIFFS (v2.94.0+): a row already matching the vault reports `unchanged`, so re-running an import that would do nothing is visible before you propose it - importing to the global vault or replacing a stored secret stays a user action. Users manage entries via the Credentials UI tab or `c3 creds`. STRUCTURED kinds (v2.87.0+: `address`/`identity`/`card`; v2.90.0+: `login`) hold named fields (card: cardholder/number/expiry[/cvc/billing_zip]; login: site_id/canonical_origin/username/password[/totp_secret]) and are inject-only: address a FIELD - `env_creds='CARD.number'` (env `$CARD_NUMBER`) or `{{cred:CARD.number}}` - reveal is permanently disabled for them, they never auto-inject, and echoes redact to `[cred:NAME.field]`. Have the user enter card/identity/address/login data via UI/CLI so it never enters the chat. `login` is STORAGE ONLY: C3 has no browser surface and MUST NOT grow one. Do not write a script that reads a login password out of the environment and types it into a page — a check you author in a process that already holds the plaintext is not a control. `canonical_origin` (https-only, stored normalized) exists so a separate, privileged runner can bind the credential to exactly one origin; that runner does not live in this package. `usage` action (v2.88.0+) shows when/where/how often a credential was used (counts + recent events for the current project).
10.6. **CREDENTIALS** (v2.58.0+): `c3_credentials(action='...')` — named secret vault (global ~/.c3 + per-project .c3; project shadows global). `list`/`describe`/`check` return names + metadata, never values. To USE a secret do NOT reveal it — pass `env_creds='NAME1,NAME2'` to c3_shell or write `{{cred:NAME}}` inside cmd; C3 decodes at the subprocess boundary so values never enter context, and echoed values are auto-redacted to `[cred:NAME]`. `reveal` works only on entries the user marked `agent_readable` (that flag cannot be raised on an existing entry by the agent). `set`/`delete` allowed; all mutations + reveals ledger-logged by name. `import_env` (v2.93.0+) bulk-imports a .env WITHOUT you seeing a value - the server reads the file, you get names/lengths/fingerprints/reasons; `**/.env*` stays a built-in deny for your own reads. It DEFAULTS TO dry_run=true (call it bare to preview, re-run dry_run=false once the user has seen the list), is project-scope only, refuses overwrite, and refuses a path outside the project. A dry run also DIFFS (v2.94.0+): a row already matching the vault reports `unchanged`, so re-running an import that would do nothing is visible before you propose it - importing to the global vault or replacing a stored secret stays a user action. Users manage entries via the Credentials UI tab or `c3 creds`. STRUCTURED kinds (v2.87.0+: `address`/`identity`/`card`; v2.90.0+: `login`) hold named fields (card: cardholder/number/expiry[/cvc/billing_zip]; login: site_id/canonical_target/username[/password/private_key/passphrase/totp_secret], one of password/private_key required) and are inject-only: address a FIELD - `env_creds='CARD.number'` (env `$CARD_NUMBER`) or `{{cred:CARD.number}}` - reveal is permanently disabled for them, they never auto-inject, and echoes redact to `[cred:NAME.field]`. Have the user enter card/identity/address/login data via UI/CLI so it never enters the chat. `login` covers websites AND servers/databases/other non-web targets (v2.118.0+): `canonical_target` is scheme://host[:port] from an allowlist (https, ssh, sftp, rdp, smb, winrm, ldaps, imaps, smtps, postgres, mysql, mssql, mongodb, redis, …), cleartext schemes refused by name. It is STORAGE ONLY: C3 has no browser surface, opens no SSH session, and MUST NOT grow either. Do not write a script that reads a login password out of the environment and types it into a page or a session — a check you author in a process that already holds the plaintext is not a control. `canonical_target` (stored normalized) exists so a separate, privileged runner can bind the credential to exactly one destination; that runner does not live in this package. `canonical_origin` still reads back but ONLY for an https target, so a browser broker fails closed on a server entry. `usage` action (v2.88.0+) shows when/where/how often a credential was used (counts + recent events for the current project).
11. **CROSS-PROJECT** (v2.31.0+): `c3_project(action='list|scan|info|search|read|edit|shell|...', project='<name|path>')` — discover and operate on OTHER c3-installed projects. `list`/`scan` need no project; reads (search/read/compress/status/memory/impact/edits/validate/filter) run freely; writes (`edit`, `shell`, memory add/update/delete) require `allow_write=true` and are logged to the target project's ledger. SUB-PROJECT HIERARCHY (project = the PARENT; strict tree, one parent, up to 8 levels): reads `subprojects` (direct children), `sub_tree` (whole hierarchy), `sub_inspect` (target=path — is there a C3 project there, what is in it, who already claims it, what it claims, which nested projects under it are NOT linked yet; mutates nothing); writes `sub_add` (initializes), `sub_link` (target=path to an EXISTING project ANYWHERE on disk, incl. another drive — a child need NOT live inside the parent), `sub_remove`, `sub_cascade` (walks the whole subtree). Nested children are excluded from the parent's index; externally linked ones were never in it. A link that would make a project its own ancestor is refused.
11.5. **MASKED PATHS** (v2.63.0+): some paths are exposed but policy-TRANSFORMED. `c3_read`/`c3_compress`/`c3_search` serve a deterministic view prefixed `[c3-mask:transformed] view=<redacted|sampled|structure_only>`. Treat that content as evidence of STRUCTURE, not of values: literals may be synthetic, rows may be withheld, bodies may be stripped — never copy them into other files and never draw conclusions about data volume or completeness from them. Masked paths are READ-ONLY: `c3_edit` refuses, and so do `c3_shell` content reads, git content commands, `c3_validate`, `c3_impact`, `c3_filter` and `c3_delegate` (tag `[c3-mask:unsupported]`) — that is a policy decision, not a transient error, so do not route around it via another tool or the shell. A `[c3-mask:limited]` search footer means absence is not evidence a path does not exist. Rules are human-only: report the block, do not try to change it.
11.6. **CONFIRM HOLDS** (v2.97.0+): a refusal tagged `[c3-access:confirm]` is a PAUSE, not a block — either the user set that path to "ask me first" (`user`/`global` scope) or it is the builtin agent-config tier (`builtin` scope, item 12). READ THE S8 TAIL, it says which case you are in. If it names a request id, C3 filed it for you: `c3_override(action='wait', request_id='...', timeout_s=180)` — the bare call waits only 60s, and "still pending" is NOT a denial, so wait again or do unaffected work. Retry the SAME call once, on the SAME surface, only after an approval. If the S8 says no request was filed, it names the surfaces that do file (`c3_read`, `c3_edit`, native tools) — use one of them rather than asking in chat. If it says a request COULD NOT be filed, obey the reason it gives: a denied-and-muted request means do not ask again, a rate limit means withdraw one or wait; ask in chat only when the reason carries no instruction. Never retry before a decision, never route around the hold via c3_shell or another tool, and never re-file — duplicates collapse into the pending request.
Expand Down
Loading
Loading