Skip to content

CLI reference - Nidvue Teamwork

Owner: Technical Writer.

Related: Home · Installation · Quickstart · Architecture · CI pipeline

Complete reference for the teamwork command-line interface. Every option below was produced from teamwork <cmd> --help.

Invocation

Three forms are equivalent:

$ teamwork <command> ...            # console script (pip install)
$ python -m teamwork <command> ...  # module
$ python3 scripts/teamwork.py <command> ...   # checkout compatibility shim

Global options

Option Meaning
--project PROJECT Project directory (default: current directory).
--team TEAM Team name (default: the project directory name).
--version Print teamwork <version> and exit 0.
-h, --help Show help for the command or subcommand.

--project and --team are accepted by every subcommand so each command can target a specific workspace.

Exit codes

Code Meaning
0 Success.
1 Generic error, a role/independence refusal, or loop says CONTINUE.
2 Usage error and the gates that explicitly return 2 (e.g. task set --status done without evidence; pr merge on an unapproved PR).
3 Nothing to dispatch (task next, pulse).
4 Lock timeout.

Setup and workspace

init

teamwork init [--agents AGENTS] [--roster {slim,standard,full}] [--force] [--no-git]

Create the team workspace and memory files; creates the git repository unless --no-git.

Option Meaning
--roster Start from a tier: slim (default: ceo, architect, developer, tester, reviewer-1, reviewer-2), standard (adds product-manager, project-manager, release-engineer) or full (all 15 roles).
--agents Comma-separated instance names, e.g. ceo,architect,developer-1,tester-1. Overrides --roster.
--force Rewrite generated scaffolding; existing memory, task records and team documents are preserved.
--no-git Do not create or check the git repository.

A tier is a recipe, not a rule. Roles left out of the roster cost no charter, no shared queue and no memory set, and their work is folded into an existing lane rather than dropped: the test matrix only requires layers of staffed roles, and the tribunal keeps a neutral seat (the Reviewer when no CTO/CFO is staffed) so no party rules its own dispute. init prints the folded lanes and warns when ceo, developer, tester or reviewer is missing.

repo

teamwork repo [--no-commit]

Ensure a git repository exists and report its status. --no-commit skips the initial commit.

map

teamwork map

Print the workspace map and the detected repository layout.

agents-md

teamwork agents-md

Create or update the managed teamwork block in <project>/AGENTS.md.

clean

teamwork clean [--all] [--dry-run] [--limit LIMIT]
               [--worktrees] [--no-worktrees] [--stale-minutes N]

Remove scratch/temp files and reclaim stale worktrees; never touches tracked files.

Option Meaning
--all Empty Scratch/ entirely, not only temp patterns.
--dry-run Show what would be removed.
--limit Cap the number of files removed.
--worktrees Reclaim merged, clean worktrees (the default; stated for clarity).
--no-worktrees Leave every worktree alone, only sweep files.
--stale-minutes Age before a merged, clean worktree is reclaimed (default 60).

A worktree is reclaimed only when all of these hold: it resolves inside the project's own .pi/, git status --porcelain --ignored is empty (a lane's build cache counts as work), its HEAD is already an ancestor of the base branch, no doing/selfcheck task or live slot lease names its lane, it is not git worktree locked, and nothing in the tree was written within the stale window. A removal that fails is reported as could not be reclaimed, never counted as success.

agents

teamwork agents

List agent directories in the workspace.

Tasks, board and scheduling

task

teamwork task {add,list,next,set,reclaim,rm} ...

Manage a role's shared priority queue.

task add

teamwork task add AGENT TITLE [--priority {P0,P1,P2,P3}]
    [--status {todo,doing,blocked}] [--deps DEPS] [--shared SHARED]
    [--tags TAGS] [--body BODY] [--bug] [--evidence EVIDENCE]
    [--claimed-by CLAIMED_BY] [--no-review]
Option Meaning
--deps Comma list of dependencies; cross-role as role:T-0001. Add @review to release once the task is submitted for review, or @started once its owner has picked it up, so a downstream lane can start against a frozen interface.
--shared Shared board / issue / PR reference.
--body Acceptance criteria / notes.
--claimed-by Assign to a specific instance (default: role pool).
--bug A defect fix: its self-check is refused until a tests repro record proves the defect.
--no-review Mark a chore that does not need Reviewer sign-off.

New tasks cannot start as review or done; the gates own those states.

task list

teamwork task list [AGENT] [--all] [--status {todo,doing,selfcheck,review,blocked,done,dropped}]

List tasks, priority ordered.

task next

teamwork task next AGENT [--peek] [--capacity N]

Atomically claim the highest-priority executable task of the role. --peek does not claim it.

Option Meaning
--peek Show what would be claimed, and claim nothing (the output lists every ready task as ALSO READY).
--capacity N Claim up to N executable tasks at once, for a lane that works in parallel; one task.claim record is written per claimed task, so trace shows each claim. 0 or a negative value is treated as 1, never as "take nothing". Default 1.

A lane that fills its capacity holds LANE_WIP (2) deliverables at once: one in review plus the next in progress. pulse uses the same arithmetic to fill each lane to its limit instead of handing work only to idle lanes; a Reviewer lane takes one deliverable at a time.

task set

teamwork task set AGENT HANDLE [--claimed-by CLAIMED_BY]
    [--status {todo,doing,selfcheck,review,blocked,done,dropped}]
    [--priority {P0,P1,P2,P3}] [--deps DEPS] [--title TITLE]
    [--evidence EVIDENCE] [--force REASON]

Update status, priority or dependencies. --force overrides evidence/self-check /review gates, requires a reason, and is recorded and audited.

task reclaim

teamwork task reclaim AGENT HANDLE --as BY --reason REASON

Take back a task whose owner went silent.

task rm

teamwork task rm AGENT HANDLE --by BY [--force REASON]

Remove a task (own role only).

board

teamwork board

Cross-agent board with counts and each role's next task.

parallel

teamwork parallel

Show free concurrency slots, ready work, and how many lanes to start.

pulse

teamwork pulse [--commit] [--interval INTERVAL]

CEO wake-up: print idle lanes, ready work and a dispatch plan. --commit applies the assignments now. --interval stores the pulse interval in minutes. Exit code 3 means nothing to dispatch.

slot

teamwork slot {acquire,release,list,renew,reap} ...

Reserve/release provider concurrency slots (respect the caps in Settings.json).

slot acquire

teamwork slot acquire --agent AGENT [--provider PROVIDER] [--task TASK] [--wait WAIT]

Take a slot; --wait seconds waits for a free one.

slot release

teamwork slot release --agent AGENT [--provider PROVIDER] [--by BY] [--force REASON]

Give a slot back.

slot list

teamwork slot list [--provider PROVIDER]

Show slots per provider.

slot renew

teamwork slot renew --agent AGENT [--provider PROVIDER]

Extend the lease while still working.

slot reap

teamwork slot reap [--provider PROVIDER]

Drop dead or stale slots.

Memory

load

teamwork load AGENT [--limit LIMIT]

Print the ROLE's short-term memory (startup context).

remember

teamwork remember AGENT TEXT [--by BY] [--src SRC] [--rev REV]
    [--layer {short,long}] [--key KEY] [--importance IMPORTANCE]
    [--tags TAGS] [--pin]

Add or update an entry in the ROLE's shared memory.

global

teamwork global TEXT [--key KEY] [--importance IMPORTANCE] [--tags TAGS] [--pin]

Add or update an entry in global shared memory (CEO-owned).

recall

teamwork recall [QUERY] [--agent AGENT] [--all] [--global]
    [--layer {both,short,long}]

Search memory.

touch

teamwork touch AGENT HANDLE [--layer {short,long}]

Mark an entry as used; HANDLE is an M-0003 id, a key, or a substring.

forget

teamwork forget AGENT HANDLE [--layer {short,long}]

Delete an entry.

consolidate

teamwork consolidate [--agent AGENT] [--all] [--dry-run]

Promote stale short-term entries and evict long-term overflow.

stats

teamwork stats [--agent AGENT] [--all]

Show memory sizes and cap violations.

Criteria and tests

criteria

teamwork criteria {add,verify,reopen,rm,list} ...

Acceptance criteria as records; they are the STOP condition.

criteria add

teamwork criteria add --id ID --text TEXT --owner OWNER --by BY

Record a verifiable statement (AC-1, AC-login, ...) and who records it.

criteria verify

teamwork criteria verify ID --by BY [--evidence EVIDENCE] [--test TEST] [--rev REV]

Mark verified with independent evidence. --by must not be the owner.

criteria reopen

teamwork criteria reopen ID --by BY [--reason REASON]

Clear a verification.

criteria rm

teamwork criteria rm ID --by BY [--force REASON]

Remove a criterion (CEO only).

criteria list

teamwork criteria list

Show criteria and status.

tests

teamwork tests {add,run,repro,require,rm,plan,list} ...

Layered tests, each owned and run by its own role.

tests add

teamwork tests add --layer LAYER [--area AREA] [--owner OWNER]
    [--task TASK] [--command COMMAND] [--no-owner-check] [--force REASON]

--layer is one of goal,requirements,plan,tech,release,data,process,cost,system,ui,docs,unit,integration,acceptance,security.

tests run

teamwork tests run ID --by BY --result {pass,fail} --evidence EVIDENCE
    [--rev REV] [--command COMMAND] [--baseline BASELINE]
    [--artifact PATH]... [--replay REPLAY] [--force REASON]

Record a layer run as an evidence packet. --artifact names a file inside the project that proves the result; it is hashed (path:sha256:bytes) and the digest is appended to the ledger. --baseline is the state before the run and --replay is the command another agent can rerun.

tests repro

teamwork tests repro TASK --by BY --pre-rev REV --pre-evidence EVIDENCE
    --post-rev REV --post-evidence EVIDENCE [--role ROLE] [--artifact PATH]...
    [--force REASON]

Prove a defect before fixing it. TASK is the defect's T-id (task add --bug), searched on every role queue (task ids are per queue, so an id that exists on several queues is refused until --role names the owner); the proof is stored on that task (repro, repro_artifacts, repro_by), not on a layer record, so it cannot leak to a sibling bug. The failing run at --pre-rev must contain fail/FAIL, the passing run at --post-rev must contain pass/PASS, and in a git workspace the pre-revision must be an ancestor of the post-revision. A --bug task cannot pass its self-check until this record exists, and audit reports a closed bug task without one.

tests require

teamwork tests require --area AREA --layers LAYERS --by BY
    [--reason REASON] [--force REASON]

Declare which layers an area must cover.

tests rm

teamwork tests rm ID --by BY [--force REASON]

Remove a test record.

tests plan

teamwork tests plan

Coverage matrix, role coverage and gaps.

tests list

teamwork tests list [--layer LAYER]

List test records.

Review and archive

review

teamwork review [AGENT] [HANDLE] [--queue] [--full] [--by BY]
    [--result {pass,fail}] [--evidence EVIDENCE] [--artifact PATH]...
    [--baseline BASELINE] [--replay REPLAY] [--findings FINDINGS]
    [--keep-branch] [--no-merge] [--force REASON]

Reviewer: independent second review of a deliverable. --queue lists everything awaiting review. A pass merges the PR at once and closes its branch: the Reviewer that verified the revision runs the merge itself, so a passing review never waits in a second queue. --keep-branch keeps the branch; --no-merge lands only the verdict and leaves the merge to pr merge. A fail returns the task to its owner. --artifact binds a verification artifact (hashed into the ledger) to the verdict; --baseline and --replay record where the verification started and how to rerun it. --force overrides the review gates and requires a recorded reason.

Independence is about the author, not about a second Reviewer: the author never reviews or merges its own work, and a Reviewer who co-authored a deliverable cannot review it. A pass that cannot merge (a conflict, a dirty tree) keeps the verdict and prints the exact pr merge to finish - the work is then not in the base branch yet, and the message says so. --queue clips each evidence and findings line at 600 characters and marks what it omitted (... (+N chars: --full)); --full prints them whole - the stored records always keep the full text.

selfcheck

teamwork selfcheck AGENT HANDLE [--by BY] [--result {pass,fail}]
    [--note NOTE] [--test TEST] [--baseline BASELINE] [--artifact PATH]...
    [--replay REPLAY] [--force REASON]

Author's own review and test before submitting for review. A passing self-check requires a --test line; --note records what was re-read, and --baseline/--artifact/--replay attach the rest of the evidence packet. A --bug task is refused until a tests repro record exists for it.

archive

teamwork archive [--agent AGENT] [--full]

Show the reviewed-result archive (the team's evidence ledger). The self-check/author evidence/reviewer evidence/findings history lines are clipped at 600 characters with an ... (+N chars: --full) marker; --full prints them whole. docs/Team/Archive.md itself always stores the full text, and pr merge rewrites only the branch / merge line of the matching entry so it records the real merge revision instead of pending - as a committed chore(records) change on the base branch, not as an uncommitted edit. The entry is written where the task's base branch is checked out, so the base carries it; a base branch that has no entry yet gets one from pr merge before the merge commit is made.

Decisions, disputes and governance

decision

teamwork decision {add,list} ...

decision add

teamwork decision add --by BY [--kind KIND] [--title TITLE] --decision DECISION
    [--why WHY] [--evidence EVIDENCE] [--context CONTEXT] [--options OPTIONS]
    [--falsify FALSIFY] [--consequences CONSEQUENCES] [--task TASK] [--rev REV]
    [--status {proposed,accepted,superseded,rejected}] [--force REASON]

--kind is one of technical,governance,redline,tribunal,scope,cost,process. A decision without evidence is refused.

decision list

teamwork decision list [--kind KIND]

List recorded decisions.

dispute

teamwork dispute {open,round,escalate,sign,resolve,list} ...

Challenge a design or decision with counter-evidence.

dispute open

teamwork dispute open --by BY --against AGAINST --topic TOPIC
    [--evidence EVIDENCE] [--position POSITION] [--task TASK]

dispute round

teamwork dispute round ID --by BY --message MESSAGE

Add a rebuttal round (capped at three, then the tribunal).

dispute escalate

teamwork dispute escalate ID --by BY

Send an unresolved dispute to CEO + CTO + CFO.

dispute sign

teamwork dispute sign ID --by BY

A tribunal member signs the ruling.

dispute resolve

teamwork dispute resolve ID --by BY --decision DECISION [--force REASON]

Record the binding ruling.

dispute list

teamwork dispute list [--open]

redline

teamwork redline {record,close} ...

redline record

teamwork redline record --by BY --action ACTION --why WHY
    [--alternative ALTERNATIVE] [--authorized AUTHORIZED]

Record a refused red-line action. Never crossed silently.

redline close

teamwork redline close ID --by BY [--reason REASON] [--force REASON]

Close a resolved red line.

skill

teamwork skill {create,share,candidates,rm,list} ...

Team skills: extract repeated flows into <project>/.agents/skills/<name>/SKILL.md.

skill create

teamwork skill create --name NAME [--role ROLE] --for DESCRIPTION --by BY
    [--body BODY] [--body-file BODY_FILE] [--force] [--allow-main]

skill share

teamwork skill share NAME --by BY [--to TO]

Notify same-role peers so they reuse it. --to is a comma list of roles, defaulting to the owner role.

skill candidates

teamwork skill candidates [--min-tasks MIN_TASKS]

Find flows worth extracting.

skill rm

teamwork skill rm NAME --by BY

skill list

teamwork skill list

Git workflow

branch

teamwork branch {start,list} ...

branch start

teamwork branch start --agent AGENT --task TASK [--base BASE] [--worktree]

Create and switch to the task branch. --worktree uses a separate worktree under Runtime/Worktrees/.

branch list

teamwork branch list

Branches with PR and merge state.

pr

teamwork pr {open,list,merge} ...

pr open

teamwork pr open --agent AGENT --task TASK [--title TITLE]
    [--summary SUMMARY] [--base BASE] [--push]

Submit a PR to the Reviewer. --push pushes the branch if a remote exists.

pr list

teamwork pr list [--open]

The Reviewer's PR inbox.

pr merge

teamwork pr merge --pr PR [--by BY] [--squash] [--keep-branch]
    [--delete-branch] [--force REASON]

Reviewer: merge an approved PR. The merged branch is deleted unless --keep-branch is given. --force overrides the review gate and requires a recorded reason. --pr takes a PR id or a task id; a task id is resolved against the task's current branch, so a task reworked after an earlier merge reaches its live PR record instead of the one already integrated in the base.

The merge always advances the base branch: a base recorded as a revision instead of a branch name is mapped back to the local branch pointing at that commit (preferring main, accepting a unique match) and refused with exit 2 when no branch points at it, because a merge built on a detached HEAD leaves the base where it was and publishes nothing. The merge runs in the work tree that has the base checked out, so a merge started from an instance worktree still lands on the base instead of failing on git checkout.

After the merge the branch / merge line of the matching docs/Team/Archive.md entry is repointed from pending to the merge revision and that one-line rewrite is committed on the base branch as its own chore(records) commit (Reviewer identity), so the archive never disagrees with the branch history and the work tree is left clean for the next merge. If the base branch has no entry for the branch yet - the review pass writes entries in whatever work tree it ran in - the accepted-results entry is appended on the base first and rides along in the same commit, so the base always records what shipped. Only an entry still saying pending is repointed: a task reworked after a merge reuses its branch name, and rewriting every match would erase the earlier merge revision from the archive.

commit

teamwork commit [--role ROLE]
    [--type {feat,fix,test,docs,design,research,refactor,perf,build,ci,chore,revert}]
    [--area AREA] [--task TASK] [--producers PRODUCERS] [--goal GOAL]
    [--deliverable DELIVERABLE] [--why WHY] [--status STATUS] [--result RESULT]
    [--docs DOCS] [--refs REFS] [--paths PATHS] [--all] [--allow-main]
    [--dry-run] [--no-check-lfs] [--lfs-threshold LFS_THRESHOLD]

Commit a change-set with the fixed style and the role commit identity.

Option Meaning
--paths Comma-separated paths to stage.
--all Stage every change.
--allow-main Override the main-branch protection (rare; explain why).
--no-check-lfs Skip the large-file LFS check (enforced by default).

identity

teamwork identity [--role ROLE]
teamwork identity --audit [--range REV..REV] [--strict-authors]

Show the role commit identity, e.g. Developer <developer@agents.nidvue.com>.

--audit fails when a commit in the range was not authored and committed by the acting role. It checks the author, the committer and the Acting role: trailer, skips the forge's synthetic pull-request merge ref, and allows bot dependency updates only when both the bot name and a users.noreply.github.com mailbox match. An author outside the team identity domain is reported as skipped by default; --strict-authors turns that into a failure. The default range is origin/main..HEAD, then HEAD~1..HEAD, then HEAD; a range beginning with - is rejected. CI runs it on every pull request and every push to main.

Audit and control

ledger

teamwork ledger {show,verify,repair,export} ...

The append-only, hash-chained audit trail.

ledger show

teamwork ledger show [--tail TAIL] [--action ACTION] [--actor ACTOR] [--target TARGET]

Inspect the trail.

ledger verify

teamwork ledger verify [--reconcile]

Recompute the hash chain. --reconcile repairs a head cache left by a crash.

ledger repair

teamwork ledger repair --by BY --reason REASON [--force REASON]

Drop a torn tail and record the repair.

ledger export

teamwork ledger export [--dry-run] [--by BY]

Write an externally verifiable audit manifest (docs/Team/AuditManifest.json).

trace

teamwork trace HANDLE [--full]

Follow one task, criterion, test or PR through every record. Free-text evidence (evidence, findings, review notes, dispute rounds, rulings) is clipped at 600 characters with an ... (+N chars: --full) marker; --full prints it whole.

teamwork links [--no-reciprocity]

Check markdown cross-links, external URLs and back-links. --no-reciprocity skips the bidirectional back-link requirement. Exit code 1 when issues exist.

audit

teamwork audit [--stale-days STALE_DAYS]

Find fabricated completions, stale work, duplicates, LFS problems and link health.

code-scanning

teamwork code-scanning [--commit] [--limit N] [--full]

Read the forge's open code-scanning alerts and route each one to the role that owns the file. The Release Engineer owns this gate: an error, critical or high alert on the default branch is a known defect in the revision that ships. Without --commit it only prints the plan (<number> [<severity>] <rule> <path>:<line> -> <role>); with it, one P0 task per (owner, rule, file) is filed in that role's queue, carrying the alert numbers and the gh api command as evidence. Re-running is safe: a title already in the queue is not duplicated.

Exit codes:

Code Meaning
0 the alerts were read and none blocks the release
1 a blocking alert is open - with or without --commit, filing a fix does not close the gate
2 the alerts could not be read: no origin, no gh, no auth, no scanner, non-JSON output

Routing follows file ownership (SCAN_ROUTE in src/teamwork/config.py): scripts/privacy_scan.py and docs/Team/AuditReport.md to the Security Auditor, src/**, scripts/** and tests/** to the Developer, .github/** and docs/Team/Release.md to the Release Engineer, docs/Team/Architecture.md to the Architect, docs/** to the Technical Writer, roles/**, references/** and templates/** to the CEO, README.md and assets/** to the Designer. An alert with no file, or a file no pattern covers, goes to the Release Engineer.

Exit 2 is the honest degraded mode: a host that is not a forge, has no gh, is unauthenticated, or has code scanning disabled prints - cannot verify: unreadable: ... and never no open alert, because nothing was verified. Fixing the code is the normal close; dismissing an alert is a Security Auditor triage with a recorded reason, never a silent one.

loop

teamwork loop

Stop-condition check: may the team stop? Prints STOP or CONTINUE with reasons.

refresh

teamwork refresh [--dest DIR] [--host HOST] [--source DIR] [--repo URL]
                 [--remote origin] [--branch main] [--mirror]
                 [--no-fetch] [--check] [--dry-run] [--quiet]

Keep the installed skill equal to the remote. The host loads the copy in its skills directory, not the checkout, so updating one without the other leaves the agent reading stale text - measured once on this machine as an old SKILL.md plus 8 engine modules that were simply missing.

  1. Resolve the source: --source, else $TEAMWORK_SOURCE, else the bundle in use when it is a git checkout, else the tool-managed mirror beside the skills directory (<skills-parent>/.teamwork-source; --mirror forces that case).
  2. In a checkout: fetch --remote/--branch and fast-forward. A dirty tree is never clobbered - the checkout is mirrored as it stands and the command says "fast-forward skipped".
  3. Mirror into --dest (default the host's skills directory). Files the source no longer ships are deleted, files outside the bundle trees are never touched, and a stale __pycache__ is removed.
  4. Print the reminder to reload the host when anything was written.

--check reports drift and exits 1 without writing; --dry-run prints the file plan; --no-fetch mirrors the local checkout only (--repo is required just once, to create the mirror). scripts/sync_skill.py and make sync-skill / make sync-check are the same mirror for a checkout that has no teamwork on PATH.

version

teamwork version

Print the version and exit (same as --version).

selftest

teamwork selftest

Offline smoke test of the install; no network, no workspace required.

model - per-agent configuration and automatic routing

teamwork model set <role|instance> --provider P --model M
teamwork model get <role|instance>
teamwork model list
teamwork model auto [--apply] [--json]

The skill ships no model and calls no LLM API: every agent runs through the host's own API, so the model is a property of the agent, not of the project.

  • set writes a role default, or an instance override when the name carries an instance suffix (developer-1). The instance wins over the role.
  • get prints the effective model and where it came from (agent, role or unset); list prints the whole roster.
  • auto reads the runtime environment - the running agent host and the model it exposes - and routes the strongest available model to the decision lanes (Reviewer, Architect, Security Auditor, CEO, CTO) and the economy model to the mechanical lanes (developers, testers, writers, formatting, link checks). It is a dry run by default; --apply writes it and records model.auto in the ledger. It never invents a model id: a lane with nothing available is reported unset together with the variable to set (TEAMWORK_MODEL_STRONG, TEAMWORK_MODEL_ECONOMY). TEAMWORK_AGENT_HOST pins host detection when the markers are ambiguous.

Automatic routing policy: references/Concurrency.md.

imaging probe

teamwork imaging probe [--json]

The Designer's capability probe for generated raster assets. It is offline by design: it reads environment variables and PATH only, never the network, so it cannot leak a prompt or hang.

Resolution order: TEAMWORK_IMAGE_MODEL (explicit override) -> TEAMWORK_IMAGE_PROVIDER -> the first ambient provider with a ranked image model, in the order openai, google, black-forest-labs, stability, replicate, local, ollama-cloud. "Best quality" is the first generally available model of the detected provider, ranked in teamwork.engine.IMAGE_MODEL_RANKING.

When no model is detected it prints the fallback ladder instead of failing: local model, then a hand-authored SVG. The full process - plan one prompt per asset in docs/Team/Design.md, generate at least four candidates off one seed base, review every candidate visually, improve the winner until it passes, integrate, record evidence - plus the privacy and licence red lines, is the Designer's own policy in roles/designer.md.

Auxiliary scripts

scripts/privacy_scan.py

python3 scripts/privacy_scan.py [--tree] [--staged] [--history] [--all]
                                [--allow FILE] [--root DIR] [--json]
                                [--reveal] [--reveal-to PATH] [--quiet]

The privacy gate. It fails (exit 1) on personal data, credentials, private domains, absolute home paths and agent-host configuration in the tracked tree, the index and the full git history. --tree, --staged and --history combine; --all sets all three; the default is --tree. Exit 2 is a usage or git error. CI runs --tree --history --allow .github/privacy-allow.txt.

Matched values are masked by default and the unmasked value is never printed. There is deliberately no flag that sends a secret to stdout or stderr: a log line survives the session (CI logs are retained and world-readable, terminals are recorded, tee output outlives the shell), so the scanner never writes one.

Plain output shows ev***et-style masked evidence, which is enough to recognise a finding in place.

Option Meaning
--reveal append a stable fingerprint to each finding line - sha256: plus 12 hex characters of the unsalted SHA-256 of the full value. Use it to tell two findings apart or to confirm that a rotated secret really is gone. It is not usable as the credential and does not embed any prefix of it
--reveal-to PATH write the raw matched values to a file you name, for local remediation only. The file is created 0600 and refuses to overwrite an existing path (exit 2); each line is location<TAB>rule<TAB>fingerprint<TAB>value; a WARNING naming the file is printed to stderr; a partial file is deleted on error
--json machine-readable report. It carries the same masked evidence; match is removed before the report is built, so the raw value is not in the JSON either
--quiet only the one-line PASS/FAIL summary
--allow FILE allowlist, one regular expression per line with an optional # reason

Remediation workflow: run with --reveal to locate and identify, then --reveal-to /a/path/only/you/can/read to recover the exact strings, rotate the credential, delete the file, and rewrite history if it was committed. Never pass --reveal-to in CI, never commit the output, and never paste it into a ticket or a chat - the file is plaintext by construction.