Can you read this tweet: https://x.com/ericzakariasson/status/2036762680401223946
Can you take a look at our CLI and based on some of the recommendations in the article, make some recommendations on how to harden our CLI to be more agent friendly.
I couldn’t read the X page directly, but I recovered the linked article from a public mirror. The title was Building CLIs for agents, and the main themes were: make commands fully non-interactive, make --help locally discoverable and example-heavy, accept stdin, fail fast with actionable errors, keep mutating commands idempotent, add --dry-run, use predictable naming, and return structured output.
What’s Already Good
share, list, setup, and remove skills already have solid JSON envelopes with ok/data/error, which is a strong base for agent usage: cli/src/commands/share.ts:721, cli/src/commands/list.ts:197, cli/src/commands/setup.ts:710, cli/src/commands/remove-skills.ts:383share already has good headless-discovery ideas: explicit selectors, env hints, and --list fallback: docs/cli.md:111--key and TRACES_API_KEY, not just browser login: docs/cli.md:83cli/src/commands/setup.ts:644, cli/src/commands/hooks.ts:127Biggest Hardening Gaps
cli/src/commands/share-options.ts:3, cli/src/commands/list-options.ts:13, cli/src/commands/setup-options.ts:3, cli/src/commands/remove-skills-options.ts:3--help, and examples are sparse: cli/src/index.ts:150, cli/src/commands/setup.ts:400status, doctor, whoami, namespace, and transfer: cli/src/commands/status.ts:66, cli/src/commands/doctor.ts:319, cli/src/commands/whoami.ts:20, cli/src/commands/namespace.ts:159, cli/src/commands/transfer.ts:5--dry-run, and confirmation behavior is inconsistent: cli/src/commands/reset.ts:58, cli/src/commands/remove-skills.ts:280, cli/src/commands/hooks.ts:201, cli/src/index.ts:265cli/src/commands/reset.ts:44Recommended Order
INVALID_ARGUMENTS with a suggestion like “did you mean --cwd?”. Right now an agent typo can silently do the wrong thing.traces <command> --help for every nontrivial command, with 2–4 concrete examples each. setup --help is the right direction; apply it everywhere.--json to every automation-relevant command and standardize on one contract: payload on stdout, diagnostics on stderr, stable ok/data/error.code/error.message.--non-interactive mode. In that mode, any prompt should become a structured error telling the caller which flags are required instead.--dry-run to all mutating/destructive commands: reset, remove skills, remove git, setup git, transfer, and uninstall.--trace-id -, --to -, or a shared --input json mode.share --cwd vs list --dir is harder for agents to infer than it needs to be; same with --key vs a clearer alias like --api-key.2 for invalid args in some commands; make that universal.If I were prioritizing purely for agent-friendliness, I’d do these first:
If you want, I can turn this into a concrete implementation plan for cli/ with command-by-command changes and suggested output schemas.
argument parsing strict < what does this mean? give example
Strict argument parsing means: if the caller passes anything invalid, the CLI errors immediately instead of silently ignoring it.
Right now some of your parsers are permissive. For example, cli/src/commands/share-options.ts:3 and cli/src/commands/list-options.ts:13 skip unknown flags, and you even test for that in cli/src/commands/share-options.test.ts:93.
Concrete example:
Current behavior:
traces share --trace-id trace-123 --jsnoWhat happens now:
--jsno is ignoredStrict behavior:
Error: Unknown option `--jsno`. Did you mean `--json`?Run `traces share --help` for examples.exit code: 2Why this matters for agents:
A few more examples of “strict”:
traces remove skills --yeespermissive: ignores typo, may open an interactive confirm prompt and hang automation
strict: Unknown option --yees. Did you mean --yes?
Missing value
traces share --trace-idstrict: Missing value for --trace-id
Invalid enum
traces share --trace-id t1 --visibility friendsstrict: Invalid value for --visibility. Use public, direct, or private.
Extra positional args
traces transfer trace-123 extra --to teamUnexpected argument extraYou already do some strict validation later in cli/src/commands/share.ts:467 for things like invalid --visibility or conflicting selectors. My recommendation was to push that strictness down into the parsing layer too, especially for unknown flags and missing values.
If you want, I can sketch what a stricter parser API would look like for share, list, and remove skills.
okay i like all your recommendations. 6 and 7 might break existsing clients so backcompat is required.
Yep — I’d treat 6 and 7 as additive, not replacements.
stdin support: keep current flags exactly as-is, and only read stdin when the caller opts in explicitly
Good backcompat pattern:
traces share --trace-id - -> read one trace id from stdintraces transfer --to team --trace-id - -> read id from stdin--from-stdin / --input json as new opt-in flagsAvoid auto-reading piped stdin just because input exists; that’s what usually breaks existing scripts
Naming normalization: add aliases, keep current names canonical internally
Good backcompat pattern:
--cwd, add --dir as alias for share--dir, add --cwd as alias for list--key, add --api-key and maybe --token as aliasesParse all aliases into the same internal field, and keep existing docs/examples working
A safe rollout would be:
--help--jsonExample of strict + backcompat together:
traces share --trace-id t1 --api-key abcThis should work because --api-key is an alias for --key.
But this should fail:
traces share --trace-id t1 --api_keey abcwith:
Unknown option `--api_keey`. Did you mean `--api-key` or `--key`?That gives you stricter agent behavior without breaking existing clients.
If you want, I can turn the recommendations into:
Do 1
Lets create a worktree and do this work in there
Set this up in a clean worktree off main so it stays isolated from the dirty current branch.
/Users/tarunsachdeva/code/traces-worktrees/feat-cli-agent-hardeningfeat/cli-agent-hardeningbun installI wrote the compatibility-safe implementation plan in docs/projects/cli-agent-hardening.md and linked it from docs/README.md.
The plan covers:
--help with examples--json coverage and exit-code cleanup--dry-run and explicit non-interactive behavior for mutating commandsNatural next steps:
Let's start
Started the first hardening slice in the worktree at /Users/tarunsachdeva/code/traces-worktrees/feat-cli-agent-hardening.
cli/src/commands/strict-parser.ts so commands can fail fast on unknown flags, missing values, and extra positional args with actionable usage textshare, list, setup, remove skills, and transfer to use strict parsing through cli/src/commands/share-options.ts, cli/src/commands/list-options.ts, cli/src/commands/setup-options.ts, cli/src/commands/remove-skills-options.ts, and new cli/src/commands/transfer-options.tscli/src/index.ts and cli/src/share-entry.ts, including JSON-shaped INVALID_ARGUMENTS errors when --json is presentcli/src/commands/share-options.test.ts, cli/src/commands/list-options.test.ts, cli/src/commands/setup-options.test.ts, cli/src/commands/remove-skills-options.test.ts, and cli/src/commands/transfer-options.test.tsVerified with:
bun test src/commands/share-options.test.ts src/commands/list-options.test.ts src/commands/setup-options.test.ts src/commands/remove-skills-options.test.ts src/commands/transfer-options.test.tsbun test src/commands/share.test.ts src/commands/list.test.ts src/commands/setup.test.ts src/commands/remove-skills.test.tsbunx tsc --noEmitNatural next steps:
--help and examples for the commands we just hardened--json to status, doctor, whoami, namespace, and transfer--dry-run / non-interactive hardening for destructive commandsCan you create a PR and share this trace to the PR
Created the PR for the first CLI hardening slice and attached the trace to it.
https://github.com/market-dot-dev/traces/pull/588https://traces.com/s/jn78srhfgeqd1mmdsxcpb2vd4x83j58yfeat/cli-agent-hardeningf26078ee (fix: fail fast on invalid CLI option parsing)I also verified the slice with:
bun test src/commands/share-options.test.ts src/commands/list-options.test.ts src/commands/setup-options.test.ts src/commands/remove-skills-options.test.ts src/commands/transfer-options.test.tsbun test src/commands/share.test.ts src/commands/list.test.ts src/commands/setup.test.ts src/commands/remove-skills.test.tsbunx tsc --noEmitIf you want, I can start the next slice in this branch: per-command --help and examples.
Please update the docs pages to reflect all these changes
Updated the docs to match the strict parsing slice and the current CLI surface.
docs/cli.md
transfer to the command list--key auth usageArgument Validation and Automation section covering fail-fast parsing, exit code 2, and JSON INVALID_ARGUMENTS errors--agent valuessetup git / remove git as availabletransfer sectiondocs/projects/cli-agent-hardening.md
Current Status section describing what’s already landed in this branchNotably, I also corrected a couple of stale docs claims:
docs/cli.md no longer says setup git / remove git are “reserved”docs/cli.md no longer implies comma-separated --agent values for setupThese doc changes are local in the worktree right now and not yet committed/pushed to the PR. If you want, I can add them to the existing PR next.
please push to the PR yes
Pushed the docs update to the existing PR.
https://github.com/market-dot-dev/traces/pull/588ced87b03 — docs: update CLI hardening guidanceI updated:
docs/cli.mddocs/projects/cli-agent-hardening.mdThis adds the new strict parsing behavior, auth notes, transfer, git hook commands, and marks the first hardening slice as complete in the project doc. No tests were run since this was docs-only.
no i don't need to add a project called cli-agent-hardening, aren't all the changes in here already, don't pollute the repo
Yep — agreed. I removed the extra planning doc and pushed the cleanup to the PR.
docs/projects/cli-agent-hardening.mddocs/README.mddocs/cli.mdPushed to the same PR:
https://github.com/market-dot-dev/traces/pull/5886e60ce64 — docs: remove extra CLI hardening planSo the repo is back to just the real CLI docs, without the extra project page.
rebase against main, this PR has conflicts
Rebased the branch onto origin/main and force-pushed the PR branch.
23e8c7e3 (origin/main)feat/cli-agent-hardening--force-with-lease, so the PR should be conflict-free nowdocs/cli.md by keeping both sets of docs updates: the newer auth/share-discovery notes from main and this PR’s strict parsing / transfer / git hook docs1bee48ac (docs: remove extra CLI hardening plan)I didn’t rerun tests since the only rebase conflict was in docs.
is this 588
Yes — this is PR #588.
https://github.com/market-dot-dev/traces/pull/588I rebased and force-pushed that PR branch.
traces share --trace-id trace-123 --jsnoError: Unknown option `--jsno`. Did you mean `--json`?Run `traces share --help` for examples.exit code: 2traces remove skills --yeestraces share --trace-idtraces share --trace-id t1 --visibility friendstraces transfer trace-123 extra --to teamtraces share --trace-id t1 --api-key abctraces share --trace-id t1 --api_keey abcUnknown option `--api_keey`. Did you mean `--api-key` or `--key`?