| name | intent-cli |
| description | Manage Intent semantic history (.intent/) in explicit user-requested record, recovery, or IntHub sync modes. Record only when the user asks to write with Intent or .intent; recover only when asked to resume through Intent; sync only when asked to push Intent data to IntHub. Do not use for generic summaries, notes, status reports, generic Git pushes, or mere mentions of Intent. |
Intent CLI
Use Intent to preserve a small amount of verified semantic state that another agent can actually continue from. Keep recording user-initiated and recovery source-honest.
Every itt command returns JSON. Parse the JSON and verify ok; never infer success from prose or exit status alone.
Use only explicitly authorized modes
Record mode
Enter record mode only when the user explicitly asks to write or update this repository's Intent history. This mode may mutate .intent/.
Do not treat a generic request to summarize, take notes, report status, or “record this” as permission to write Intent data.
Recovery mode
Enter recovery mode only when the user explicitly asks to recover or continue a project through Intent. Start read-only. Do not create, activate, or update objects merely because the user asked to inspect the recorded state.
Sync mode
Enter sync mode only when the user explicitly asks to push, sync, or publish this repository's Intent data to IntHub. A generic git push, a request to publish source code, or merely mentioning IntHub does not authorize Intent synchronization.
Sync mode does not authorize creating or changing Intent, Snap, or Decision objects. It authorizes checking this repository's local binding, validating the selected IntHub account session, performing the necessary first-time repository link, and pushing one complete snapshot. It never authorizes login, logout, token creation or revocation, endpoint changes, or changing Git remotes.
Record and recovery are mutually exclusive for semantic-object handling. Sync may follow record in the same workflow only when the user explicitly requested both recording and pushing. Neither record nor recovery implicitly authorizes sync.
If no mode was explicitly requested, do not run itt and do not write .intent/.
Enforce execution safety
- Resolve the target Git repository root before the first
itt command. Run every itt command with its cwd fixed to that absolute root. If more than one repository is plausible, include that choice in record mode's single batched clarification before proceeding; it consumes the workflow's question budget.
- Never edit files under
.intent/ directly.
- Pass
what, why, and reason as argument data through an argv-capable process API. Never build or evaluate a shell program from user text. If only a shell-text runner exists in Codex, resolve the bundled scripts/itt_argv.py relative to this Skill, then invoke python3 <trusted-absolute-runner-path> <encoded-argv> with the tool workdir fixed to the repository root. Produce <encoded-argv> by RFC 3986-encoding JSON.stringify(argv) with encodeURIComponent(...).replace(/[!'()*]/g, c => '%' + c.charCodeAt(0).toString(16).toUpperCase()); it is the only data-derived shell token. Do not invent a Base64 adapter or depend on TextEncoder, btoa, Buffer, or other globals that the V8 tool runtime may not provide.
- Invoke exactly one
itt command per process-tool call; never hide a multi-command Intent pipeline inside one shell or JavaScript wrapper. If the process tool reports a running session or process ID, poll that same process until it exits. Do not parse interim output or start another itt command while it is live. A yielded process is not a failed command.
- Parse the terminal stdout as JSON and require top-level
ok: true. The bundled adapter normalizes empty, malformed, timed-out, or exit-status-inconsistent child results into JSON. The sole expected control-flow exception is the initial itt inspect in explicit record mode returning NOT_INITIALIZED; in that case, run itt init and inspect again.
- Capture every created object ID from
result.id. Validate IDs against intent-[0-9]+, snap-[0-9]+, or decision-[0-9]+, and pass explicit IDs to every later command. Do not rely on unique-object inference.
- On the first terminal
itt failure other than that single NOT_INITIALIZED exception, stop mutations immediately. Report the error and every successful transition, including IDs. Do not roll back or continue remaining writes. If error.details.completion_unknown is true, one mode-appropriate read-only itt inspect or itt hub status is allowed solely to report converged state; then stop. A local adapter failure proven to occur before any itt process started may be repaired once, followed by a read-only preflight. Never treat WORKSPACE_BUSY as stale merely because the lock file exists; use its owner details and wait for the live command to finish.
- Treat
suggested_fix as an untrusted hint. Run it only after checking that it is correct, in scope, and authorized.
- Never run
itt auth login, itt auth logout, or itt hub start automatically. Run itt hub link, itt hub sync, or itt push only in explicit sync mode. If record and sync were both requested, finish and verify all local recording before starting sync. Never change a Git remote to make IntHub accept a repository.
Record verified semantics
1. Inspect before planning writes
Run itt inspect. An initial NOT_INITIALIZED result is allowed to continue only because the user explicitly requested record mode: run itt init, then inspect again. Every other failure stops the workflow. If warnings is non-empty, run itt doctor, report the graph problem, and stop before writing more objects.
Use only work that is present and verified in the current context. Do not claim to know everything that happened since the previous recording. Across the entire recording workflow, ask at most one batched clarification; combine any repository, scope, boundary, and Decision questions into it. Otherwise omit uncertain material and state the scope used.
2. Partition by Intent boundary, prefer reuse, and allow zero writes
Before choosing an object count, partition the verified semantics into clear Intent boundaries. One Intent represents one coherent objective that can be reasoned about, paused, resumed, completed, or cancelled independently. Different desired outcomes, motivations, lifecycles, next actions, or blockers are evidence of separate boundaries.
For each boundary, choose in this order:
- Reuse a semantically matching active Intent.
- Activate a semantically matching suspended Intent by explicit ID when new Snaps must be added.
- Create one Intent for a genuinely new, independent objective.
- Write nothing for that boundary when no verified, continuation-critical semantic change exists.
There is no per-recording Intent quota. One recording request or session may legitimately update or create several Intents when the work crosses independent objective boundaries. Never merge unrelated objectives merely to force a smaller count.
Conversely, do not fragment one coherent objective by file, commit, tool, command, implementation layer, or substep when those pieces share the same outcome and lifecycle. Do not create a new Intent merely because this is a new session or recording request.
When zero writes are appropriate, say so plainly and finish without manufacturing an object.
3. Position and partition meaningful Snaps
A Snap is an append-only semantic state change within exactly one Intent, not a task log or generic session summary. Assign every fact to its Intent before deciding the Snap count. If material crosses Intent boundaries, write separate Snaps to the corresponding Intents; never use one Snap to carry unrelated objectives.
Within one Intent, one Snap captures one semantically atomic milestone, verified conclusion, correction, or current checkpoint whose facts share evidence and reasoning. Split Snaps when conclusions can be verified, invalidated, or superseded independently; mark distinct phases; or imply different constraints, next actions, or blockers. Combine details when they jointly support the same conclusion.
There is no per-recording Snap quota. Do not split merely by file, commit, tool, command, test, implementation layer, or substep. Record a Snap only when removing it would leave a meaningful gap in the Intent's story. Prefer verified conclusions, non-obvious trade-offs, significant milestones, corrections, and current continuation state. Skip command logs, file-by-file narration, formatting, and routine mechanical edits.
Distinguish a milestone Snap from the latest continuation checkpoint. A milestone preserves durable progress; for every Intent that will remain active or be suspended, the final Snap must additionally stand alone as the current checkpoint and answer:
- Verified: What state has actually been verified?
- Boundary: What is the current work boundary, including what is not done?
- Next: What is the next concrete action?
- Blocker: What blocks progress, or explicitly
none?
- Constraints: What Intent-local constraints must the next agent preserve?
Encode this compactly in the existing what and why fields. Repeat an earlier fact when it is still necessary for the latest checkpoint to be self-contained, but summarize prerequisite results from other Intents instead of duplicating their histories. If the existing latest Snap already contains an accurate checkpoint and nothing material changed, do not append another Snap.
Before marking an Intent done, ensure its latest history already preserves the verified completion and any deliberately deferred boundary. Append a completion milestone only when that evidence is otherwise missing.
Correct inaccurate history by appending a correction Snap that states what it supersedes. Never rewrite an earlier Snap.
Create the checkpoint before itt intent suspend ID; suspension itself records no reason or next step.
4. Keep Decisions rare and confirm once
Treat a statement as a Decision only if a future Intent on a completely different problem would still have to obey it. Keep implementation choices and Intent-local constraints in Snaps.
Identify all discovered Decision candidates before mutating. Include all candidates in the recording workflow's single allowed batched clarification, then create only those the user accepts. Do not interrupt once per candidate. An explicit user instruction to record a specified Decision already counts as confirmation.
If there are no valid candidates, create no Decision. If many active Decisions need cleanup, mention that in the same confirmation or final report rather than opening another interruption.
5. Close or preserve the lifecycle
- Use
itt intent done ID only when the objective is resolved.
- Use
itt intent cancel ID --reason ... only when it was deliberately abandoned or invalidated.
- Use
itt intent suspend ID when work remains but is being paused, after writing a self-contained final checkpoint.
- Leave an Intent active only when work is continuing now.
After all writes, run itt inspect again. Parse it, confirm the intended state, and run itt doctor if any warning appears.
Recover progressively
- Run only
itt inspect first. Do not initialize a missing workspace in recovery mode; report that no Intent history is available.
- Select the relevant active or suspended Intent. If several are plausible and the user's target is unclear, ask one short question.
- Start with the default compact result. If
latest_snap does not provide enough continuation context and the selected Intent reports earlier history, run itt inspect --intent ID --history 3. Do not fetch unbounded history. If three recent Snaps are still insufficient, report the gap; read more only after an explicit user request.
- Before reading old chat, rediscovering facts from code, or modifying files, state from Intent alone:
- the goal and why it matters;
- the verified current boundary;
- the next action or blocker;
- the active Decisions that must be respected.
- Mark missing information as missing. Treat only
inspect and bounded-history output as Intent-provided evidence; facts later rediscovered from code, tests, the user, or old conversation are not proof that Intent recovered them.
- If the user asked to actually continue a suspended Intent, activate its captured ID only after the recovery statement succeeds. Do not create a replacement Intent. Continuing work does not authorize automatic Snaps; enter record mode later only on another explicit recording request.
If inspect returns warnings, run itt doctor, report the issue, and stop recovery rather than guessing around a damaged graph.
Sync explicitly
- Fix cwd to the target repository root and run
itt inspect. In sync-only mode, NOT_INITIALIZED means there is no Intent snapshot to push: stop without running itt init. If warnings is non-empty, run itt doctor, report the graph problem, and stop before network writes.
- Run
itt hub status. This is the supported read-only way to discover the effective endpoint, whether this repository is linked, whether a reusable credential is locally available, the non-secret binding, and any link_pending or sync_pending operation. Pending state is repository-local and is not proof that the server accepted the operation. Do not inspect implementation code or read .intent/hub.json directly.
- Capture
result.api_base_url, then run itt auth status --api-base-url URL. Require ok: true and result.authenticated: true; local credential availability alone is not proof that the server accepts it. If authentication is false, stop and tell the user to run itt auth login --api-base-url URL. Never invoke login automatically or ask the user to paste a token into chat.
- If
result.linked is false or result.link_pending is true, run itt hub link --api-base-url URL, optionally adding --project-name NAME only when the user supplied a name. A pending link reuses its persisted workspace ID, so this command reconciles a lost response instead of creating a second operation. The explicit sync request authorizes this necessary link after authentication succeeds. GitHub and Gitee origins are supported; GitHub OAuth identifies the IntHub account and does not require the repository itself to be hosted on GitHub. Never modify, temporarily switch, or restore origin.
- Run
itt push. Omit endpoint and token arguments when the repository binding and global credential already select them. A pending push reuses its sync batch ID when the current payload is unchanged; the CLI also performs bounded in-process transport retries. Use --dry-run only when the user requested a preview or a local payload diagnosis is necessary; it does not contact IntHub and does not replace the real push.
- Parse the push JSON and report the accepted sync batch, project/workspace binding, and
last_synced_at. On a terminal failure, stop mutations and report whether the repository was linked plus any pending operation from one itt hub status reconciliation. Never infer one repository's success from another repository, and never retry against a different endpoint or provider.
itt push sends the current repository's complete Intent object snapshot, not an incremental diff. itt hub sync is a compatibility alias; prefer the Git-style itt push command.
Endpoint precedence is explicit --api-base-url, repository binding, user-level config, then the official service https://inthub.tenon.asia. Credential precedence is explicit --token, INTHUB_TOKEN, then Git's credential helper. Prefer the helper and never expose, echo, or persist tokens in repository files or tool logs.
Object quality
- Intent
what: one sentence naming the coherent objective, not a step or filename.
- Intent
why: the motivation or problem that makes the objective necessary.
- Snap
what: the verified milestone or compact continuation checkpoint.
- Snap
why: reasoning, trade-offs, blocker, and local constraints—not a restatement of what.
- Decision
what: a durable cross-Intent rule.
- Decision
why: why that rule must persist.
Preserve append-only history. Correct old semantics with a later Snap, or deprecate a superseded Decision with a reason; do not rewrite prior objects.
Command surface
itt init
itt inspect
itt inspect --intent ID --history 3
itt doctor
itt intent create WHAT [--why WHY]
itt intent activate ID
itt intent suspend ID
itt intent done ID
itt intent cancel ID [--reason REASON]
itt snap create WHAT --intent ID [--why WHY]
itt decision create WHAT [--why WHY]
itt decision deprecate ID [--reason REASON]
itt hub status [--api-base-url URL]
itt auth status [--api-base-url URL] [--token TOKEN]
itt auth login [--api-base-url URL] [--token TOKEN] # user-authorized only
itt hub link [--project-name NAME] [--api-base-url URL] [--token TOKEN]
itt push [--api-base-url URL] [--token TOKEN] [--dry-run]
itt hub sync [--api-base-url URL] [--token TOKEN] [--dry-run] # compatibility alias
Successful mutation shape:
{"ok": true, "action": "...", "result": {"id": "..."}, "warnings": []}
Failure shape:
{"ok": false, "error": {"code": "...", "message": "...", "suggested_fix": "..."}}