Core Workflow
td manages the full lifecycle of issues from creation through review, with structured handoffs between AI sessions to prevent context loss.
Creating Issues
Create issues with a title, type, and optional priority:
td create "Add user authentication" --type feature --priority P1
td create "Login button misaligned" --type bug
td create "Refactor auth module" --type task --priority P2
td create "Capture sync edge cases" --description-file docs/issue-description.md
Types: bug, feature, task, epic, chore
Priorities: P0 (critical) through P4 (lowest). Defaults to P2 if omitted.
For markdown-heavy descriptions or acceptance criteria, prefer --description-file and --acceptance-file. They preserve blank lines, indentation, and fenced code blocks exactly, and - reads the whole field from stdin:
cat docs/acceptance.md | td update td-a1b2 --append --acceptance-file -
Starting Work
Pick up an issue to work on:
td start td-a1b2 # Begin work, sets status to in_progress
td next # Show highest-priority open issue
td focus td-a1b2 # Set current focus without changing status
td start transitions the issue to in_progress and records which session is working on it. Use td focus when you want to track what you're looking at without formally starting work.
Logging Progress
Record decisions, blockers, and findings as you work:
td log "OAuth callback working"
td log --decision "Using JWT for stateless auth"
td log --blocker "Unclear on refresh token rotation"
td log --hypothesis "Token refresh might conflict with SSO"
td log --tried "Attempted session-based approach, too complex"
td log --result "Benchmarks show 2ms token validation"
Logs attach to your current focus issue. They build a timeline that future sessions can read to understand what happened and why.
Handoffs
Handoffs are the key feature of td. They capture structured state so the next session can pick up work without guessing:
td handoff td-a1b2 \
--done "OAuth flow, token storage" \
--remaining "Refresh token rotation" \
--decision "Using JWT for stateless auth" \
--uncertain "Should tokens expire on password change?"
Each field serves a purpose:
- --done: What was completed this session
- --remaining: What still needs to be done
- --decision: Choices made and why (prevents re-litigating)
- --uncertain: Open questions for the next session to resolve
Without handoffs, the next AI session starts from scratch, re-reads code, and may redo work or contradict earlier decisions. Handoffs eliminate that waste.
Review Workflow
Submit completed work for review:
td review td-a1b2 # Submit for review (status -> in_review)
td reviewable # Issues you can independently review
td reviewable --include-approved # Also show reviewed issues you can close
td approve td-a1b2 # Approve and close
td reject td-a1b2 --reason "Missing error handling" # Back to open
Independent review is preferred when practical. In the default trusted mode,
an implementer who cannot get one is asked to say who reviewed the work:
# A sub-agent reviewed it — credit them (no reason required)
td approve td-a1b2 --reviewed-by "code-reviewer sub-agent"
# You reviewed your own work — say so
td approve td-a1b2 --self-review --reason "Reviewed own diff; tests pass"
Both are recorded on the review row, and neither is verifiable by td. Naming a reviewer who did not review is worse than an honest self-review, because it reads as independent in the audit trail.
Review Policy Modes
td exposes four policy modes via review_policy_mode:
trusted— default for new installs. Prefers independent review; an involved session may approve by naming who reviewed the work (--reviewed-by "<who>") or acknowledging a self-review (--self-review --reason). Both are audited. Supports--record-only.delegated— review attestations with delegated close. Reviewer independence is enforced; any session may perform the final close once an independent approval review has been recorded.strict— no prior involvement allowed on the reviewer at all. Preserved for orchestrators that want the legacy close-time session lock.balanced— strict, plus a creator-approval exception (see below). Retained for projects that explicitly opt in.
The legacy balanced_review_policy flag is deprecated; prefer review_policy_mode=balanced instead. Setting the legacy flag still works but emits a one-time deprecation warning.
Set the mode per-project or via env:
td feature set review_policy_mode strict # or trusted, delegated, balanced
# or, one-off:
TD_FEATURE_REVIEW_POLICY_MODE=strict td approve td-a1b2
Balanced (Legacy) — Creator Exception
Under balanced, a session that created a task (but didn't implement it) can approve with a reason:
- Implementer self-approval is always blocked — if you started or worked on a task, you can't approve it.
- Creator-approval is allowed when a different session did the implementation, with
--reason. - All other previously-involved sessions remain blocked.
# Lead creates work, agent implements, lead approves
td add "Build feature X"
td start td-a1b2 # agent session
td review td-a1b2
td approve td-a1b2 --reason "Reviewed output, looks good" # lead session
Creator-exception approvals are audited in td security.
Delegated — Review Attestations and Delegated Close
Under delegated, the review step and the close step are separate:
- A reviewer session records an approval (or requests changes) via
td approve --record-only --reason "...". - Once an approval review exists, any session may close with
td approve --reason "...".
Two flows are natural under this mode:
Direct reviewer-close — the reviewer both approves and closes in one step:
td review td-a1b2
td approve td-a1b2 # reviewer session: approve + close
Record approval, close later — a reviewer sub-agent attests, and the orchestrator or implementer closes when convenient:
td review td-a1b2 # orchestrator submits
td approve td-a1b2 --record-only --reason "Reviewed diff, tests pass" # reviewer records
td approve td-a1b2 --reason "Closing after recorded independent approval" # orchestrator closes
The second flow is the typical orchestrator pattern. The orchestrator does not need to reserve a special issue role; the independent approval is the close gate, and closed_by_session records who performed the final close.
A reviewer can also record a non-approving decision:
td approve td-a1b2 --record-only --decision changes_requested --reason "fix X"
Use td reviewable --include-approved to surface reviewed issues you can close.
Issue Lifecycle
open --> in_progress --> in_review --> closed
| |
v | (reject)
blocked -----------+
- open: Created, not yet started
- in_progress: Actively being worked on
- blocked: Waiting on a dependency (auto-unblocks when all dependencies close)
- in_review: Implementation complete, awaiting review
- closed: Approved and done
Rejection sends an issue back to in_progress with a reason attached, so the implementer knows what to fix.
Session Isolation
Every terminal or context window gets an automatic session ID. This keeps implementation, review, and closure attributable without dictating how much ceremony every task needs.
Why this matters:
- Supports structured handoffs between sessions
- A fresh session reading the code with new eyes catches issues the implementer missed
- Distinguishes independent review from acknowledged self-review
- Mirrors real code review, where a different person checks the work
Let sessions reflect real agent contexts. Creating a new session merely to make a review appear independent defeats the audit trail; use an independent context or acknowledge a trusted-mode self-review instead.
Under delegated mode the review must be independent but the close may be
delegated to any session. Under balanced mode, a creator-approval exception
allows the same session that created a task to approve it once a different
session implemented it.