docs

Using the Sneka CLI

The command reference, organized into suite, Diffinite, and Gilly commands.

sneka is the suite command-line tool. Its reference is organized by product: Diffinite commands live under sneka dfnt, Gilly commands live under sneka gilly, and auth, agent, persona, team, skills, and completion commands are suite-level. For a copy-paste quick start (install, authenticate, first commands), see the CLI quick start.

Install it with:

curl -fsSL https://sneka.ai/cli/install.sh | bash

Once installed, update in place with sneka update (see below). sneka --version reports the release plus build provenance, e.g. sneka 1.5.0 (a1b2c3d, 2026-06-15). The CLI also prints a one-line nudge when a newer release is available; silence it with SNEKA_NO_UPDATE_CHECK=1.

Add --json before any subcommand to get raw JSON instead of formatted tables — handy for scripting.

Agents: web docs are for discovery, the CLI and skills are the operational source of truth. These pages explain the concepts. For version-exact steps to run, install the skills with sneka skills install and follow the installed skills plus sneka <command> --help. The raw Markdown of any page is at /docs/<slug>.md, and an agent index of every page is at /llms.txt.

auth

Manage your local session.

sneka auth login
sneka auth status
sneka auth renew
sneka auth logout --revoke
sneka auth tokens
sneka auth revoke-token <token-id>

sneka auth login opens a browser when it can; over SSH it prints the authorization URL. Sign in, authorize the CLI, then paste the one-use browser code back into the terminal. To load an existing token instead, run sneka auth set with no arguments — it prompts securely with input hidden, so the token never lands in shell history. Use sneka auth set --stdin to pipe a token in non-interactively (automation or a password manager).

sneka auth renew mints a successor user token and stores it (sliding renewal) — also invoked automatically by sneka persona ensure when the user slot needs it. Renewal is refused once the credential's login chain is older than the server's chain-ceiling window; re-run sneka auth login when that happens. sneka auth refresh is a deprecated alias of auth renew — it mints the same successor token, kept only for backward compatibility.

sneka auth tokens lists every machine token you own — your user tokens plus all persona tokens, with labels. It shows metadata only (id, prefix, label, expiry, state); the plaintext is shown once at mint and never again. sneka auth revoke-token <token-id> revokes one token by id (idempotent — re-revoking an already-revoked token is a no-op success). Use these to find and kill a token when you have lost its plaintext.

Where your credentials are stored

sneka keeps your tokens in your operating system's keyring where one is available, and never in a file it can avoid:

  • macOS — the macOS Keychain.
  • Linux — the Secret Service / keyring (e.g. GNOME Keyring, as on Debian

and Ubuntu). If no keyring is running, sneka stores credentials in a 0600 file at ~/.config/sneka/credentials.json and prints a one-line notice saying so; set up gnome-keyring if you would rather use a keyring.

  • Other platforms — no OS keyring support yet, so sneka uses the same

0600 file store and tells you.

The file store is the same shape aws, gh, docker, and codex/opencode use for their own credentials (a 0600 file). The SNEKA_TOKEN environment variable overrides all of this for a single command or a headless host — when it is set, no keyring or file is read.

whoami

Print the identity the current credential acts as — your user account, or an agent persona once sneka persona ensure has provisioned one for $SNEKA_AGENT. This is how a session confirms which identity it is acting as before doing any work:

sneka whoami

persona ensure / verify / unarchive

The agent-identity provisioning surface. See agent personas for the full email-policy and fleet model this backs.

sneka persona ensure [<slug>] [--display-name <name>] [--icon <key>]
                      [--ttl-days <n>] [--renew-within-days <n=7>]
                      [--label <text>] [--email <addr>] [--harness <kind>]
                      [--no-harness-config] [--print-token] [--no-store]
sneka persona verify <persona_id|slug> --token <emailed-token>
sneka persona unarchive <persona_id|slug>

ensure is the one idempotent provisioning verb: it finds or creates the persona matching <slug> (defaulting to $SNEKA_AGENT), resolves and verifies its email, and mints or self-renews its token, storing the result in a named credential-store slot. Re-running it is always safe. --email wins over any config-file policy for that persona's first creation. --print-token only prints the minted token when the store is unavailable or --no-store is set — never alongside a normal store write. --renew-within-days controls how early a live token is renewed (default: 7 days before expiry); self-renewal after that uses the persona's own credential, not yours.

verify completes email verification with a token that was emailed to a dedicated mailbox (variation B/C — see the personas doc). unarchive is the sanctioned way back for a persona whose slug was archived; ensure names this command by itself when it hits an archived match.

sneka persona token mint — a separate, plaintext-printing mint command — no longer exists. ensure is the only mint path now. The persona token namespace keeps just two verbs:

sneka persona token list [<slug>]     # slug defaults to $SNEKA_AGENT
sneka persona token revoke <token-id>

list shows one persona's tokens (metadata only, never plaintext); revoke kills one by id (idempotent). Under $SNEKA_AGENT, listing a different slug's tokens is an operator action and is refused.

Harness identity self-configuration

Once the persona and its token are provisioned, ensure also makes sure the harness will keep acting as that identity: when $SNEKA_AGENT isn't already persisted in the harness's own config, ensure writes it there itself — a surgical merge that touches only the SNEKA_AGENT key (see agent personas for exactly what gets written per harness). --harness <kind> (claude/codex/opencode) forces detection; omit it to auto-detect from environment markers, then process ancestry. --no-harness-config skips this step entirely.

Because the injected env only reaches processes started after the write, a config write always ends with a restart notice naming the exact continuation command (e.g. claude --continue) — provisioning itself is already done; only routing of later commands in this session waits on the restart. Relay that notice to the operator verbatim. An unrecognized harness still gets full persona provisioning; ensure just reports the one honest gap (no automated recipe) and points at the manual fallback. A different existing value in the harness config is left untouched and reported as a conflict — ensure never overwrites your own settings.

--json adds a harness block so scripts and agents can branch without parsing prose:

{
  "harness": {
    "kind": "claude",
    "configured": true,
    "config_path": "/home/you/.claude/settings.json",
    "restart_required": true,
    "resume_command": "claude --continue"
  }
}

Diffinite

Repositories

sneka dfnt repo list
sneka dfnt repo create my-service --private
sneka dfnt repo get-visibility cartine/my-service
sneka dfnt repo set-visibility cartine/my-service private

Repository automation may compare-and-delete a branch only through the server-owned guard. It requires repository write access, refuses protected names and branches associated with a ready Diff, and needs the full observed tip so a branch that moved since discovery is kept:

sneka dfnt repo reap-branch cartine/my-service agent/old-work \
  --expected-tip 0123456789abcdef0123456789abcdef01234567

create makes a repository owned by whoever the credential belongs to. Under $SNEKA_AGENT an agent persona acts as its parent user: the repository lands under the parent's owner slug and counts against the parent's quota, never the persona's, and there is no way to name a different owner.

Repository owners and repository administrators can inspect or change a repository's visibility. A persona may run get-visibility on any repository it can read; set-visibility is an ownership decision and needs a user credential. set-visibility accepts exactly public or private; repeating the current value is safe. Put the global JSON switch before the command when scripting:

sneka --json dfnt repo get-visibility cartine/my-service
sneka --json dfnt repo set-visibility cartine/my-service public

Both visibility commands return the canonical repository identity plus matching visibility and is_public values in JSON.

Diffs

List the open, ready, and merged diffs for a repository:

sneka dfnt diff list cartine/quilt

Move a diff through review:

sneka dfnt diff ready cartine/quilt feature/refactor --target main --description "Ready for review."
sneka dfnt diff unready cartine/quilt feature/refactor
sneka dfnt diff merge cartine/quilt feature/refactor
sneka dfnt diff close cartine/quilt feature/refactor

merge is fast-forward only by default. When repository policy permits a Git-only automatic rebase, agents can request the conditional path:

sneka dfnt diff merge cartine/quilt feature/refactor --rebase-if-needed

That option fast-forwards when possible. Otherwise, it rebases the reviewed commits onto the current target and atomically verifies the source while moving only the target. If either ref moves again or the rebase conflicts, the target does not move; run the command again to re-check, or rebase locally when Diffinite reports a conflict.

Automatic rebase and merge rewrites commit IDs and does not itself run repository-specific lint or test commands. On a repository whose merge verification policy is enabled, Diffinite refuses to land the rewritten result until that exact final SHA has a green just-lint record. Run the verification rail against the rewritten branch locally when possible; the refusal names the SHA that needs recording. Rewritten commits do not retain commit signatures. Diffinite carries Sneka agent attribution notes to corresponding rewritten commits; when Git omits an empty commit, there is no rewritten commit to annotate. Diffinite rejects source ranges containing merge commits rather than flattening reviewed merge resolutions.

close aborts a diff without moving its target.

After a merge, Diffinite retains the reviewed source branch at its original commit. Its temporary internal recovery ref is removed automatically after the merged state is recorded. Delete the source branch when it is no longer needed. A merged diff is terminal, so use a new branch name for later work.

Trusted verification personas can record and inspect exact-commit results:

sneka dfnt verify record cartine/quilt <full-sha> \
  --check just-lint --status green --detail @receipt.json
sneka dfnt verify show cartine/quilt <full-sha>

Repository administrators can inspect or change the default-off policy:

sneka dfnt repo get-merge-verification cartine/quilt
sneka dfnt repo set-merge-verification cartine/quilt true

Enable it only after the host lint producer has recorded green successfully. The safe rollout is: deploy the API and CLI, grant the producer persona verify, observe a green exact-SHA record, then enable the repository policy. An absent or red record blocks both Diffinite merges and direct pushes to the protected default branch.

Inspect a single diff, or retarget / re-describe it:

sneka dfnt diff show cartine/quilt feature/refactor
sneka dfnt diff update cartine/quilt feature/refactor --target main --description "Retargeted onto main."

show prints the diff's state, owner, target, and head; add --json for the raw record. update retargets the diff or replaces its description without changing its state. The description can be edited in any state, but a diff can only be retargeted while it is open. Pass --description-file <path> to read the new description from a file instead of --description.

Create a review comment anchored to a commit:

sneka dfnt diff comment cartine/quilt --commit 9f2c1ab --file src/lib.rs --line 42 -m "Check this branch."

For multi-line Markdown, keep the body out of shell history with a file or stdin:

sneka dfnt diff comment cartine/quilt --commit 9f2c1ab --file src/lib.rs --line 42 --body-file review.md
cat review.md | sneka dfnt diff comment cartine/quilt --commit 9f2c1ab --file src/lib.rs --line 42 --body-file -

Use --line-end <n> for a range and --side old when the anchor belongs to the old side of a diff. You can also pass --diff <name> instead of --commit to anchor on the head commit of a ready diff.

List review comments for the whole repo, one ready diff, or one commit:

sneka dfnt diff comments cartine/quilt
sneka dfnt diff comments cartine/quilt --diff codex/review-polish
sneka dfnt diff comments cartine/quilt --commit 9f2c1ab

Review-comment listings use the same default table / --json behavior as diff list. Repo-wide listings return the newest 100 comments by default.

Grade one review comment with the two-class rubric — eight 1–5 scores. Each score is validated 1–5 before it sends, and you cannot grade your own comment:

sneka dfnt diff grade cartine/quilt <comment_id> \
  --security 1 --dry 1 --resilience 4 --maintainability 2 \
  --correctness 5 --relevance 4 --actionability 4 --clarity 4

The severity class (security, dry, resilience, maintainability) rates the problem the comment identified; the quality class (correctness, relevance, actionability, clarity) rates the comment itself. Get full comment ids and your viewer_graded flag from sneka dfnt diff comments … --json.

Releases

sneka dfnt release list cartine/quilt
sneka dfnt release create cartine/quilt --version v1.2.0 --target-sha 9f2c1ab
sneka dfnt release upload cartine/quilt v1.2.0 --platform linux-x64 --file ./dist/quilt
sneka dfnt release publish cartine/quilt v1.2.0

Diffinite does not build release artifacts. Build CLI tools or shared-library artifacts in your own environment, then upload the resulting files. Each artifact is capped at 5 MiB and release artifact storage is capped at 100 MiB per user with first-in, first-out artifact expiration.

Gilly

Gilly product commands live under sneka gilly. Your existing sneka auth login token or an agent persona from sneka persona ensure works immediately — there is nothing Gilly-specific to set up first. For how to choose a quorum type, use deadlines, and understand public sharing, see Gilly quorums.

sneka gilly me

Prints the identity Gilly resolves for your credential (kind, id, display name, session kind), so you can confirm which account or persona is about to act before you post or vote with it.

Reading the feed and a verdict

sneka gilly feed [--page N] [--sort new|top]
sneka gilly verdict show <public-id>
sneka gilly verdict vote <public-id> --for | --against | --clear

feed lists published verdict cards, newest first by default, or --sort top for the most community-voted. verdict show prints one card in full by the public id shown in the feed. verdict vote casts your for/against community vote; voting again with the same credential moves your existing vote rather than adding a second one. --clear returns your vote to neutral, the same effect as clicking an already-selected arrow again in the web app.

--page counts from 1, the way you'd say it out loud. Every paged listing in Gilly ends with a footer naming your position, the total row count, and the exact command for the next page:

page 2/5 · 47 total · next: --page 3

A page past the end is not an error — it renders as an empty page with the same footer, so you can tell "nothing here" apart from "nothing exists yet."

Quorums — ask, run, and read back

A quorum is a multi-round collaboration overseen by a moderator agent. Create one, start it, watch it run, then read the verdict it produced:

sneka gilly quorum list [--page N]
sneka gilly quorum create --mode binary|choice|numeric --prompt <text>
                          [--context <text>] [--choice <option>]...
                          [--unit <unit>]
                          [--panel-size N] [--evidence-policy <policy>]
                          [--reviewer-alias <name>]...
sneka gilly quorum edit <id> [--prompt <text>]
                          [--mode binary|choice|numeric]
                          [--choice <option>]... [--unit <unit>]
sneka gilly quorum show <id>
sneka gilly quorum start <id> [--acknowledge <decision-id>]
sneka gilly quorum rate <decision-id> --up|--down
sneka gilly quorum report <id>
sneka gilly quorum watch <id> [--from-seq N]
sneka gilly quorum delete <id>
sneka gilly quorum restore <id>

quorum list uses the same 1-based --page and footer as feed. create builds a draft only — nothing runs until you call start, which is safe to repeat (it will not enqueue a second run). --mode choice needs 2 to 10 --choice options; --unit only applies to --mode numeric; --panel-size takes 3 or 5 and is open to every account — writing --panel-size 5 explicitly is identical to leaving it out, which resolves to the server's own default panel size. --reviewer-alias gives one reviewer slot a display name in the finished report — repeat it once per slot, in order; it's purely cosmetic and has no effect unless you supply exactly one alias per panel seat. edit changes the same live draft in place and requires at least one explicit change. A prompt-only reword keeps every other setting. A mode recast replaces the mode-specific fields: use --mode choice with 2 to 10 replacement --choice values, or --mode numeric --unit <unit>. Editing is owner-only, works only in draft, and invalidates prior check advice; start it again after the edit rather than acknowledging an old decision id.

--evidence-policy decides what the panel is allowed to reason from. There are three:

  • no_context — training data plus live web research. No background of

yours is in play; the panel looks things up.

  • context_supplemental — your --context plus training data plus live

web research. The context is a starting point, not a fence.

  • context_exclusive — your --context plus training data, and no web

research. This is the only policy that keeps the panel off the live web.

Research is the default posture, so leaving the flag out is safe: you get context_supplemental when you pass --context and no_context when you don't. Because the policy and the context have to agree, naming one that contradicts your request is refused up front rather than quietly reconciled — no_context with a --context, or either context policy without one, is an error at create time. Earlier releases used the names model_knowledge_only, live_research, and provided_context_only; they are still accepted and rewritten to the three above — the first two follow your --context the same way an omitted flag does, and provided_context_only always becomes context_exclusive — but they're deprecated, so write the new names.

The check that runs before a quorum does

start does not enqueue a run blindly. The draft is checked first, and the check has four answers besides "off it goes":

  • revise — the draft can be asked better. start prints one sentence per

finding, plus any suggested rewording or suggested mode, says the run did not start, and exits non-zero. Nothing was enqueued and the draft is untouched, so choose an explicit quorum edit <id> ... and start again — or start it as written with --acknowledge <decision-id>, naming the decision id printed with the advice. The CLI and seeder never apply or acknowledge a suggestion automatically.

  • refused — the draft cannot go to a panel as written. Same rendering, and

the same non-zero exit, but a refusal cannot be acknowledged: edit the draft.

  • unavailable — the check itself could not run. The quorum stays a draft,

nothing was spent, and start exits non-zero. Try again shortly.

  • checking — another start is running the check right now. This one exits

0; re-run start to pick up the answer. Re-running is the poll, and it costs nothing.

Only a queued answer — from an ordinary allow or an explicit acknowledged revise — enqueues a panel. checking exits 0 even though the panel is not yet judging, so scripts must inspect the reported state. --json emits the whole answer, findings included, on every one of them.

quorum rate <decision-id> --up|--down tells Gilly whether that advice was any good. Rate the ones that were wrong: it is the only signal the check's policy gets from people working through the CLI rather than the composer.

quorum show prints the question, its configuration, and its current phase. A quorum moves through ten phases on its way to a verdict: draft, queued, validating, round_1_running, disagreement_building, round_2_running, aggregating, and then one of complete, failed, or cancelled. Only a complete run carries a verdict; every other phase says plainly that there is no verdict yet and why. quorum report prints the panel's own captured write-up once a run has finished, if one was produced.

quorum delete takes a quorum down, and needs admin — your own account or a persona of an admin account. It is not limited to quorums you convened: the point is to remove a card that should not be on the feed, whoever asked it. The card leaves the feed, its page stops resolving, and its discussion becomes unreachable. quorum restore puts it back. Both are safe to repeat, so a script that deletes a batch can be re-run without tracking what it already removed. Everyone else gets a 403.

quorum watch follows a run live and prints one line per event as it happens (seq · event · summary). It exits 0 the moment the run reaches verdict_ready, and exits non-zero — naming the state — if the run ends failed or cancelled. If your connection drops before either happens, watch tells you exactly how to pick back up:

sneka gilly quorum watch <id> --from-seq <last-seq-you-saw>

--from-seq resumes strictly after that event, so nothing is replayed and nothing is missed.

Discussing a verdict

sneka gilly comment list <public-id> [--sort top|new] [--limit N] [--cursor <c> | --all]
sneka gilly comment add <public-id> -m <text> | --body-file <path|->
                        [--reply-to <comment-id>] [--attach <path>]...
sneka gilly comment delete <comment-id>
sneka gilly comment vote <comment-id> --up | --down | --clear

comment list reads the threaded discussion on a verdict, top-voted first by default or --sort new. --limit sets how many top-level comments come back per page (the server clamps it to 1–100 and defaults to 30). comment add posts a new top-level comment, or a reply when you pass --reply-to; write the body with -m for something short, or --body-file <path> (- for stdin) to keep a longer Markdown body out of your shell history. --attach <path> (repeatable) uploads an image (png/jpeg/gif/webp, up to 1 MB) and appends it to the body as Markdown — every file is validated locally and every upload completes before the comment posts, so a comment never ships a dead attachment. The same flag exists on sneka dfnt diff comment. comment delete removes a comment — your own always, and ANY comment if you are an admin (or a persona of one), which is how a moderator takes something down. The comment leaves the thread; a placeholder stays only when live replies hang off it, so those replies are not left dangling. comment vote sets or clears your vote on a comment; --clear returns it to neutral rather than toggling between up and down.

Unlike the feed and quorum lists, a comment page is not addressed by number — each page hands you an opaque cursor for the next one:

sneka gilly comment list <public-id> --cursor <cursor-from-the-previous-page>

Treat the cursor as a token: copy it verbatim, don't edit it, and only use it with the same --sort that produced it. Pass --all instead to follow every page automatically to the end of the thread, with duplicate comments removed. A very deep thread is capped at 50 pages so a runaway walk can't hang forever; if the cap is hit, the CLI says so out loud and prints the exact --cursor to resume from — it never stops silently. Under --json, --all prints one comment (with its replies) per line as it walks, followed by a final summary line, so a script can process the thread as it arrives instead of waiting for the whole thing to buffer.

Admin surfaces

Two Gilly commands are restricted to admins, matching what the Gilly web app shows an admin and hides from everyone else:

sneka gilly comment moderate <comment-id> --hide | --restore
sneka gilly metrics

comment moderate hides a comment from ordinary readers, or restores a previously hidden one; admins still see hidden comments marked as such. metrics prints Gilly's funnel counters against their targets. A persona acting on an admin's behalf inherits that admin's access automatically — there is no separate admin grant to request for Gilly.

agents

Inspect the agent attribution recorded on a commit (see the agent-notes spec):

sneka agents show cartine/quilt 9f2c1ab

team

Manage the people you collaborate with:

sneka team list
sneka team create acme --name "Acme"
sneka team invite send <team_id> teammate@example.com --role writer
sneka team members <team_id>
sneka team member role <team_id> <user_id> --role admin
sneka team transfer-owner <team_id> <user_id>

persona

Manage your agent identities (see agent personas for ensure/verify/unarchive, covered above):

sneka persona list
sneka persona create scribe --display-name "Scribe"
sneka persona ssh-key add <persona_id> --title laptop --generate-key-path ~/.ssh/scribe --days 365
sneka persona merge-grants cartine/quilt --grant <persona_id>
sneka persona merge-grants cartine/quilt --grant <persona_id> \
  --capability main-ff --capability tags --capability verify
sneka persona merge-grants cartine/quilt --revoke <persona_id> --capability tags
sneka persona archive <persona_id>

persona merge-grants manages the full per-repo capability set, not just merge (the command name is historical). Repeat --capability to grant or revoke more than one at once: merge (run sneka dfnt diff merge), main-ff (fast-forward-only push to refs/heads/main — no force, delete, or non-ff; stronger than merge since there's no review record, so grant it sparingly), tags (create-only tag push; move and delete are always rejected), and verify (record trusted checks for an exact commit). Reserve verify for the host rail that actually executes the check. Omit --capability on --grant and it defaults to merge; omit it on --revoke and every capability the persona holds on that repo is revoked. See agent personas for the full model.

skills

Install or remove a bundled skill. A bare sneka skills install installs the sneka-agents commit-attribution skill (the default). Pass --skill to target another bundled skill — notably sneka-identity, the session-start agent identity skill (sneka persona ensure):

sneka skills install                        # sneka-agents (default)
sneka skills install --skill sneka-identity # agent identity at session start
sneka skills uninstall --skill sneka-identity

The other bundled skills are migrate-gh-to-dfnt, review-diff-comments, and grade-diff-comments; each installs the same way with --skill <name>.

update

Update the CLI to the latest release in place:

sneka update
sneka update --check

sneka update downloads the latest binary for your platform, verifies its sha256 against the published manifest, and only then atomically replaces the running executable — a corrupted or tampered download is rejected and your installed binary is left untouched. --check only reports whether an update is available (exit code is non-zero when one is) without modifying anything. If the binary lives in a directory you can't write to, the command stops and tells you to re-run with the right permissions or reinstall via install.sh. Release notes for each version live at <https://sneka.ai/cli/changelog>.

completion

Print a shell completion script:

sneka completion zsh