- JSONL append-only events (
.tasque/events.jsonl) are the sole source of truth. Derived state (.tasque/state.json) is a rebuildable cache — never edit it manually. - Single-machine write lock via
.tasque/.lock(open wx, short retry). No multi-writer guarantees. - Snapshot loader scans newest-to-oldest valid snapshot; writes prune to latest 5 files.
- Git repos default to sync-worktree mode on
tsq init: main worktree keeps.tasque/config.json; task data lives intsq-syncunless--sync-branchor--worktree-namenames another branch/worktree. Legacy git repos with main-tree.tasquedata auto-migrate on the next command. 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. - Event IDs are ULIDs. Canonical event field is
idwith legacyevent_idalias accepted on read. Task IDs are 8-char Crockford base32 random (root) or<parent>.<n>(children, append-only). - TasqueService is split into focused Rust modules:
src/app/service.rs(facade),src/app/service_types.rs,src/app/service_utils.rs,src/app/service_lifecycle*.rs(mutations),src/app/service_query.rs, plus notes/specs/labels modules. Internal modules receive aServiceContextobject. - Status transitions emit
task.status_setevents; non-status field updates emittask.updated. Supersede/duplicate emit both. - Shared helpers:
src/domain/events.rs(event factory),src/cli/terminal.rs(width/density), dependency tree helpers insrc/domain/dep_tree.rs. - JSON output uses a universal envelope with
schema_version=1.
- Bidirectional
relates_tolinks; canonicalsupersedecloses the source task and setssuperseded_bywithout dependency/link rewiring. duplicatecloses source, addsduplicate_ofmetadata - no dependency rewiring (same pattern as supersede).- Strict CAS (compare-and-swap) claim semantics.
- Spec required sections:
Overview,Constraints / Non-goals,Interfaces (CLI/API),Data model / schema changes,Acceptance criteria,Test plan. - Timestamp filters (
--created-after,--updated-after,--closed-after) require strict ISO timestamps; reject natural-language dates. - There is no task re-parent command; to split/move a subtree, create a new epic/feature branch and use
supersedelinks from old tasks to new IDs for durable traceability. - TUI v2 visual baseline is Beads-inspired but Tasque-native: dark navy shell, top tabs
Tasks|Epics|Board(optionalReady|History), dense pill tables, fixed 3-column board, and explicitSpecstate (attached|missing|invalid) visible in table rows, board cards, and inspector.
- Human-readable CLI color/styling must stay TTY-aware and honor
NO_COLOR/CLICOLOR=0(with optionalCLICOLOR_FORCE) so automation/tests remain plain-text stable while interactive shells get richer output. resolve_task_idreturnsTASK_NOT_FOUND, notNOT_FOUND.- Negated search queries (
-field:value) need a--separator before them becauseclaptreats leading-as option flags. clapoption conflict detection (e.g.--assigneevs--unassigned) must handle both--flag valueand--flag=valueforms consistently.- Lock contention timeout (
LOCK_TIMEOUT) is a concurrency-class failure and must keepexitCode: 3(not IO/storage code 2). - Query tokenizer must handle
field:\"quoted value\"as one token; quote handling only at token-start breaks field-prefixed quoted filters. with_write_lockreturnsINTERNAL_ERRORwhen both callback and lock release fail; keep release failure visible instead of masking it behind the callback error.- Stale lock cleanup uses atomic
rename+ content verification to prevent TOCTOU races between concurrent cleaners. - Projector validates dep/link targets with
requireTask()— repair tests must inject orphans via state cache, not raw events, to bypass this validation. repair --fixcomputes plan inside write lock using locked snapshot to prevent plan/apply drift.- CLI command handlers return explicit
i32exit codes; do not reintroduce global process exit state that can leak between in-process command runs. clapmay report no-subcommand cases asDisplayHelpOnMissingArgumentOrSubcommand(not onlyMissingSubcommand); for hard default no-arg behavior (like TUI entry), prefer an explicit pre-parseargs.len()==1TTY check and then handle both error kinds in fallback parsing paths.- On Windows, replacing a compiled
tsq.execan fail withEPERMif a prior test or shell still holds the binary; stop the process and retry the Cargo build. - For new CLI-option coverage before a fresh release build, run tests against
cargo run -- ...or rebuild first to avoid stale-binary false failures.
cargo build --release --lockedcompiles the Rust binary; release workflows emit platform artifacts +SHA256SUMS.txtindist/releases/.- Release automation should pass the freshly built
dist/tsq(.exe)path into release-note generation instead of relying ontsqfromPATH; this keeps GitHub runners and local environments deterministic. tsq initskill lifecycle for agents uses managed-marker semantics: install, uninstall, idempotent update, non-managed skip unless--force.- Versioning/release planning baseline: use
Cargo.tomlas version source, surface via CLI-V/--version, and automate release PR/tag flow with release-please + GitHub Actions artifact publishing. - Added
node npm/scripts/bump-version.jshelper to bumpCargo.toml,Cargo.lock, root npm package, and platform package versions; supports--dry-run. release-please.ymlnow supportsworkflow_dispatchfor manual release-PR refresh from GitHub Actions.- Release workflows enforce tag/version sync against
Cargo.toml. - Added
release-from-package.ymlworkflow: manual dispatch creates a GitHub release fromCargo.tomlversion and then the publish workflow handles artifact builds.
- Wizard contract baseline: run
tsq initwizard only on TTY by default;--no-wizardis authoritative;--wizardis TTY-only; non-interactive agent flows must remain fully deterministic via flags. - Refined wizard UX contract (docs/design/init-wizard-design.md): preserve a 4-step max flow, always show resolved plan before writes, treat
--yesas wizard auto-accept (no-op outside wizard), and keep preset semantics deterministic (minimal,standard,full) with explicit-flags-over-preset precedence. - Explicit skill actions (
--install-skill/--uninstall-skill) should bypass auto-wizard mode sotsq initexecutes immediately;--wizardis still available to force interactive flow.
- 2026-02-18: Event parsing validates JSONL boundaries via typed Rust/serde parsing; canonical event field is
idwhile reads still accept legacyevent_id. - 2026-02-18: Cache path migrated to
.tasque/state.jsonwith backward-compatible reads from legacy.tasque/tasks.jsonl. - 2026-02-18: Planned workflow model approved: keep lifecycle
statusseparate from newplanning_state; adddeferredlifecycle status;readyshould surface both planning and coding lanes with optional lane filter; create defaults toplanning_state=needs_planning; add--body-file, strict--idregex, and deferred follow-up tasks fordiscovered-from+ typed dependency model expansion. - 2026-02-18: Implemented
discovered_fromprovenance metadata end-to-end (create/update/list/search/show) and typed dependency edges (blocks|starts_after) with directional filters/search (--dep-type/--dep-direction,dep_type_in/out); onlyblocksaffect ready/cycle checks. - 2026-02-18: Skill installer now sources managed skill content from on-disk packages under
SKILLS/<name>/and recursively copies package contents (including references/scripts) to target agent skill directories. - 2026-02-19: In Rust file-based parent modules (e.g.
src/app/service.rs,src/domain/projector.rs), sibling module splits need explicit#[path = "..."] mod ...;to prevent Rust from resolving into implicit subdirectories (service/...,projector/...). - 2026-02-19: Rust 2024 edition treats
genas a reserved keyword; calls likerand::thread_rng().gen::<u8>()must use raw identifier syntax (r#gen) or an alternate API. - 2026-02-19:
claprepeatable CSV options withvalue_delimiter=','can silently admit empty tokens unless validated explicitly; parity with TS requires rejecting--id ""/--label-any ""as--<field> must not be emptyand inputs likea,,bas--<field> values must not be empty. - 2026-02-19: Rust watch parity with TS requires non-fatal refresh failures in loop mode (keep last good frame + print refresh error) and TTY-gated clear-screen/interactive controls; exiting on first refresh error is a behavioral regression.
- 2026-02-19: Stable Rust hygiene baseline for this repo: pin toolchain components (
rustfmt,clippy), keeprustfmt.tomlaligned tostyle_edition=2024, and enforcecargo fmt --check+cargo clippy --all-targets --all-features -- -D warningsin CI to prevent drift.