This file contains detailed storage, task model, CLI contract, and project conventions. Referenced from AGENTS.md.
Git repositories default to sync-worktree mode:
tsq initconfigures thetsq-syncbranch/worktree unless--sync-branch <name>or--worktree-name <name>names a custom branch/worktree.- data operations are redirected to the configured sync worktree
- legacy main-tree
.tasquedata migrates automatically when nosync_branchis configured - fresh clones fetch the configured sync branch and create the worktree on first use
tsq syncpushes the sync branch tooriginand sets upstream automatically when needed- the main worktree keeps
.tasque/config.jsonas the pointer to the sync branch
Non-git directories use repo-local .tasque/:
.tasque/events.jsonl(canonical source of truth, append-only).tasque/state.json(derived cache, rebuildable, gitignored).tasque/tasks.jsonl(legacy state-cache name; read-only fallback whenstate.jsonis absent; removal target).tasque/snapshots/(replay checkpoints, local by default).tasque/config.json(project settings).tasque/.lock(ephemeral write lock)
Event fields:
id(ULID, canonical)event_id(legacy alias accepted on read)ts(ISO datetime)typeactortask_idpayload
Event types:
task.createdtask.updatedtask.status_settask.claimedtask.notedtask.spec_attachedtask.supersededdep.addeddep.removedlink.addedlink.removed
Read path:
- resolve configured sync worktree when
sync_branchis set - migrate legacy git repos to the default sync worktree when no
sync_branchis set - load latest snapshot (if any)
- replay event tail
- refresh
state.jsoncache
Write path:
- append event(s)
- update projection
- periodically write snapshot
Task fields:
id(tsq-<number>root,<parent>.<n>child); legacytsq-<8 crockford base32 chars>IDs remain validalias(kebab-case slug generated from the creation title; stable across title edits)kind(task|feature|epic)titlestatus(open|in_progress|blocked|deferred|closed|canceled)planning_state(needs_planning|planned)priority(0..3)assignee(optional)parent_id(optional)superseded_by(optional)duplicate_of(optional)replies_to(optional)discovered_from(optional provenance metadata)labels[]created_at,updated_at,closed_at
Dependencies:
- edge:
child -> blockerwithdep_type(blocks|starts_after) - semantics: only
blocksparticipates in ready/cycle checks;starts_afteris non-blocking ordering metadata
Relation types:
relates_to(bidirectional)replies_toduplicatessupersedes
tsq(no args, TTY): open read-only TUItsq init [--wizard|--no-wizard] [--yes] [--preset <name>] [--sync-branch|--worktree-name <name>]tsq init --install-skill|--uninstall-skill [--skill-targets ...] [--skill-name <name>] [--force-skill-overwrite]tsq skills refresh— update managed skill files across all targets; repo-independent (notsq initor.tasque/required)tsq create <title...> [--kind ...] [-p ...] [--parent <id>] [--from-file tasks.md] [--description <text>] [--external-ref <ref>] [--discovered-from <id>] [--planned|--needs-plan] [--ensure] [--id <id>] [--body-file <path|->] [--force]tsq show <id> [--with-spec]tsq find ready [--lane <planning|coding>] [--assignee <name>] [--unassigned] [--kind ...] [--label ...] [--planning <needs_planning|planned>] [--tree [--full]]tsq find <blocked|open|in-progress|deferred|done|canceled> [filters...] [--tree [--full]]tsq find search <query> [--full]tsq find similar "<text>"tsq watch [--once] [--interval <seconds>] [--status <csv>] [--assignee <name>] [--tree] [--flat]
Notes:
- For
find readyand status-basedfindcommands,--fullis only valid with--tree.--tree --fullkeeps the full status set instead of applying the default tree status narrowing.find search --fullremains valid without--tree. --id <id>acceptstsq-<number>or legacytsq-<8 crockford base32 chars>.- Commands that accept a task ID also accept exact aliases and unique alias prefixes unless
--exact-idis used. tsq find similar "<text>"shows ranked duplicate candidates with scores and reasons.tsq createrefuses similar open/in-progress/blocked/deferred tasks unless--forceis passed.
watch renders the task tree by default for human output. Use --tree to explicitly request tree view or --flat for the compact list view. These options are mutually exclusive.
tsq tui [--once] [--interval <seconds>] [--status <csv>] [--assignee <name>] [--board|--epics]tsq stale [--days <n>] [--status <status>] [--assignee <name>] [--limit <n>]tsq doctortsq repair [--fix] [--force-unlock]tsq edit <id> [--title ...] [--description ...] [--clear-description] [--priority ...] [--external-ref <ref>] [--clear-external-ref] [--discovered-from <id>] [--clear-discovered-from]tsq claim <id> [--assignee <a>] [--start] [--require-spec]tsq assign <id> --assignee <a>tsq start <id>tsq planned <id>tsq needs-plan <id>tsq open <id>tsq blocked <id>tsq defer <id> [--note <text>]tsq done <id...> [--note <text>]tsq reopen <id...> [--note <text>]tsq cancel <id...> [--note <text>]tsq orphanstsq spec <id> [--file <path> | --stdin | --text <markdown> | --show | --check] [--force]tsq spec <id> --update [--file <path> | --stdin | --text <markdown>]tsq spec <id> --patch [--file <path> | --stdin | --text <patch>]tsq block <task> by <blocker>tsq unblock <task> by <blocker>tsq order <later> after <earlier>tsq unorder <later> after <earlier>tsq deps <id> [--direction <up|down|both>] [--depth <n>]tsq relate <src> <dst>tsq unrelate <src> <dst>tsq duplicate <id> of <canonical-id> [--note <text>]tsq duplicates [--limit <n>]tsq merge <source-id...> --into <target-id> [--reason <text>] [--force] [--dry-run]tsq supersede <old-id> with <new-id> [--note <text>]tsq note <id> <text>tsq note <id> --stdintsq notes <id>tsq label <id> <label>tsq unlabel <id> <label>tsq labelstsq history <id> [--limit <n>] [--type <event-type>] [--actor <name>] [--since <iso>]tsq sync [--no-push]tsq hooks install [--force]tsq hooks uninstalltsq migrate [--sync-branch|--worktree-name <name>]tsq merge-driver <ancestor> <ours> <theirs>
Global options:
--format human|json--jsonshorthand for--format json--exact-id
Status alias:
done -> closed
Planning workflow guidance:
- Treat lifecycle
statusandplanning_stateas separate dimensions. tsq find ready --lane planningsurfaces tasks that need planning work (planning_state=needs_planning).- Planning-lane work should collaborate with the user and update specs/task body as needed before coding.
- Use
tsq spec <id> --updatefor full spec replacement andtsq spec <id> --patchfor small agent edits. Prefer patch input via stdin/file so unified-diff---headers are parsed as content. tsq find ready --lane codingsurfaces tasks already planned (planning_state=planned).- Use
status=deferredfor valid work intentionally parked for later.
Exit codes:
0success1validation/user error2storage/IO error3lock/concurrency failure
All commands support:
{
"schema_version": 1,
"command": "tsq ...",
"ok": true,
"data": {}
}Error:
{
"schema_version": 1,
"command": "tsq ...",
"ok": false,
"error": { "code": "VALIDATION_ERROR", "message": "..." }
}- single-process lock via
.tasque/.lock(open wx) - lock timeout
3s; jitter20-80ms - stale cleanup only if same host and PID confirmed dead
- append-only event log
- atomic cache writes (
state.json.tmp-*-> rename) - startup recovery ignores one malformed trailing JSONL line with warning
- deterministic rebuild from snapshot + event tail
- reads legacy
.tasque/tasks.jsonlonly as a fallback state cache; do not write new data there
- commit
.tasque/events.jsonland.tasque/config.json - do not commit
.tasque/state.json - do not create or edit
.tasque/tasks.jsonl - snapshots optional to commit (default local-only)
- do not manually edit generated cache files
- one clear code path over abstractions
- no plugin system
- no backend interface layer until second backend exists
- target file size < 500 LOC
- use
cargo fmtandcargo clippy - keep strict typing
- build the binary and place it in
~/.local/binso that it is available in the cli as tsq. - run
cargo fmt --check,cargo clippy --all-targets --all-features -- -D warnings, andcargo test --quiet. Fix any issues that arise. - use a fix forward approach and avoid unnecessary complexity of backward compatibility in mind. We are in active development.
- keep the codebase organized and modular. Refactor as needed to improve readability and maintainability.
- Lookup if a refactor task already exists before creating a new one. If it doesn't create one so we can track it.