home / skills / tkersey / dotfiles / st

st skill

/codex/skills/st

This skill helps you persist and review durable task plans in your repo with JSONL, ensuring continuity across sessions.

npx playbooks add skill tkersey/dotfiles --skill st

Review the files below or copy the command above to add this skill to your agents.

Files (9)
SKILL.md
6.5 KB
---
name: st
description: Manage persistent task plans in repo-committed JSONL (`.step/st-plan.jsonl`) so state survives turns/sessions and stays reviewable in git. Use when users ask to "use $st", "resume the plan", "export/import plan state", "checkpoint milestones", "track dependencies/blocked work", "show ready next tasks", "keep shared TODO status on disk", "compare and contrast $st vs plan files", or when work has 3+ dependent steps and transient `update_plan` is not durable enough.
---

# st

## Overview

Maintain a durable plan file in the repo (default: `.step/st-plan.jsonl`) using in-place JSONL v3 persistence with dual lanes:

- `event` lane for mutations
- `checkpoint` lane for periodic full-state snapshots

Plan items use typed dependency edges (`deps: [{id,type}]`) plus `notes` and `comments`, and render deterministically through `show`/read views.

## Workflow

1. Resolve repository root and plan path.
2. If the run has 3+ dependent steps, likely spans turns, or already uses `update_plan`, adopt `$st` as the durable source of truth before editing.
3. Initialize plan storage with `scripts/st_plan.py init` if missing.
4. Rehydrate current state with `scripts/st_plan.py show` (or focused views via `ready` / `blocked`).
5. Apply plan mutations through script subcommands (`add`, `set-status`, `set-deps`, `set-notes`, `add-comment`, `remove`, `import-plan`); do not hand-edit existing JSONL lines.
6. After each mutation command, consume the emitted `update_plan: {...}` payload and publish `update_plan` in the same turn.
7. Use `emit-update-plan` to regenerate the payload from durable state when needed.
8. Export/import snapshots when cross-session handoff is needed.

## Commands

Run commands from the target repository root.

```bash
CODEX_SKILLS_HOME="${CODEX_HOME:-$HOME/.codex}"
CLAUDE_SKILLS_HOME="${CLAUDE_HOME:-$HOME/.claude}"
ST_PLAN="$CODEX_SKILLS_HOME/skills/st/scripts/st_plan.py"
[ -f "$ST_PLAN" ] || ST_PLAN="$CLAUDE_SKILLS_HOME/skills/st/scripts/st_plan.py"
ST_QUERY="$CODEX_SKILLS_HOME/skills/st/scripts/st_query_fast.sh"
[ -f "$ST_QUERY" ] || ST_QUERY="$CLAUDE_SKILLS_HOME/skills/st/scripts/st_query_fast.sh"

uv run "$ST_PLAN" init --file .step/st-plan.jsonl
uv run "$ST_PLAN" add --file .step/st-plan.jsonl --id st-001 --step "Reproduce failing test" --deps ""
uv run "$ST_PLAN" add --file .step/st-plan.jsonl --id st-002 --step "Patch core logic" --deps "st-001"
uv run "$ST_PLAN" set-status --file .step/st-plan.jsonl --id st-001 --status in_progress
uv run "$ST_PLAN" set-deps --file .step/st-plan.jsonl --id st-002 --deps "st-001:blocks,st-003:blocks"
uv run "$ST_PLAN" set-notes --file .step/st-plan.jsonl --id st-002 --notes "Need benchmark evidence"
uv run "$ST_PLAN" add-comment --file .step/st-plan.jsonl --id st-002 --text "Pausing until CI clears" --author tk
uv run "$ST_PLAN" ready --file .step/st-plan.jsonl --format markdown
uv run "$ST_PLAN" blocked --file .step/st-plan.jsonl --format json
uv run "$ST_PLAN" show --file .step/st-plan.jsonl --format markdown
uv run "$ST_PLAN" emit-update-plan --file .step/st-plan.jsonl
uv run "$ST_PLAN" export --file .step/st-plan.jsonl --output .step/st-plan.snapshot.json
uv run "$ST_PLAN" import-plan --file .step/st-plan.jsonl --input .step/st-plan.snapshot.json --replace
```

## Operating Rules

- Keep exactly one `in_progress` item unless `--allow-multiple-in-progress` is explicitly used.
- Track prerequisites in each item's typed `deps` array; dependencies are part of the canonical JSONL schema.
- Parse CLI deps as comma-separated `id` or `id:type` tokens; missing type normalizes to `blocks`, and type must be kebab-case.
- Require dependency integrity:
  - dependency IDs must exist in the current plan,
  - no self-dependencies,
  - no dependency cycles.
- Allow `in_progress` and `completed` only when all dependencies are `completed`.
- Normalize user status terms before writing:
  - `open`, `queued` -> `pending`
  - `active`, `doing` -> `in_progress`
  - `done`, `closed` -> `completed`
- Mutation commands (`add`, `set-status`, `set-deps`, `set-notes`, `add-comment`, `remove`, `import-plan`) automatically print an `update_plan:` payload line after durable write.
- Lock sidecar policy: mutating commands require the lock file (`<plan-file>.lock`, for example `.step/st-plan.jsonl.lock`) to be gitignored when inside a git repo; add it to `.gitignore` before first mutation.
- Mutations rewrite the JSONL file atomically (`temp` + `fsync` + `os.replace`) and compact to a canonical `replace` event plus checkpoint snapshot at the current seq watermark.
- `import-plan --replace` atomically resets state in the same in-place write model.
- Prefer concise, stable item IDs (`st-001`, `st-002`, ...).
- Prefer `show --format markdown` for execution: it groups steps into `Ready`, `Waiting on Dependencies`, `In Progress`, and terminal/manual buckets.

## Fast Query Helper (`jq` + `rg`)

- Use `scripts/st_query_fast.sh` for low-latency read-only queries against large logs.
- Requires both `jq` and `rg` on `PATH`.
- Examples:
  - `"$ST_QUERY" --file .step/st-plan.jsonl ready`
  - `"$ST_QUERY" --file .step/st-plan.jsonl blocked`
  - `"$ST_QUERY" --file .step/st-plan.jsonl show`
  - `"$ST_QUERY" --file .step/st-plan.jsonl show st-002`

## Sync Checklist (`$st` -> `update_plan`)

- After each `$st` mutation (`add`, `set-status`, `set-deps`, `set-notes`, `add-comment`, `remove`, `import-plan`), parse the emitted `update_plan: {...}` line and publish `update_plan` in the same turn.
- If no emitted payload is available (for example after `init` or shell piping), run:
  - `uv run "$ST_PLAN" emit-update-plan --file .step/st-plan.jsonl`
- Preserve item ordering from `$st` in `update_plan`.
- Map statuses:
  - `in_progress` -> `in_progress`
  - `completed` -> `completed`
  - `pending`, `blocked`, `deferred`, `canceled` -> `pending`
- Keep dependency edges only in `$st` (`deps`); do not encode dependencies in `update_plan`.
- If an item has `dep_state=waiting_on_deps`, never publish that step as `in_progress` in `update_plan`.
- Before final response on turns that mutate `$st`, re-check no drift by comparing:
  - `uv run "$ST_PLAN" show --file .step/st-plan.jsonl --format json`
  - the latest emitted `update_plan` payload.

## Validation

- Run lightweight CLI sanity checks:
  - `uv run "$ST_PLAN" --help`
  - `uv run "$ST_PLAN" emit-update-plan --file .step/st-plan.jsonl`
  - `uv run "$ST_PLAN" show --file .step/st-plan.jsonl --format json`

## References

- Read `references/jsonl-format.md` for event schema, status/dependency state vocabulary, and snapshot import/export shapes.

Overview

This skill manages a durable, repo-committed task plan using an in-place JSONL file (default: .step/st-plan.jsonl) so state survives turns, sessions, and is reviewable in git. It provides mutation commands, deterministic read views, and a lightweight sync protocol to publish update_plan payloads after each change. The model uses an event lane plus periodic checkpoint snapshots for efficient and auditable state.

How this skill works

The tool initializes and rehydrates plan state from a JSONL file that contains typed events and full-state checkpoints. Mutations (add, set-status, set-deps, set-notes, add-comment, remove, import-plan) write atomic JSONL entries and emit a single update_plan payload line that callers must parse and publish. Read-only helpers show ready/blocked/in-progress views and fast query scripts use jq + ripgrep for low-latency inspections.

When to use it

  • When you need persistent, git-reviewable TODO state that survives sessions and turns.
  • When you want to checkpoint milestones and export/import plan snapshots between environments.
  • When you need to track typed dependencies and block/unblock work deterministically.
  • When you want a single canonical in-repo source for shared task status and comments.
  • When you must publish an update_plan payload after edits for downstream sync.

Best practices

  • Keep short, stable item IDs (st-001, st-002...) and prefer show --format markdown for execution views.
  • Do not hand-edit existing JSONL lines; use the provided mutation commands to preserve integrity.
  • Ensure .step/st-plan.jsonl.lock is gitignored before first mutation to avoid committing locks.
  • Allow exactly one in_progress item unless you explicitly enable --allow-multiple-in-progress.
  • Validate deps: ensure referenced IDs exist, prevent self-deps and cycles, and normalize types to kebab-case.

Example use cases

  • Resume a paused plan across chat turns: run show, then set-status to in_progress and publish update_plan payload.
  • Checkpoint a milestone before a risky change: run export to create a portable snapshot for handoff.
  • Find next ready tasks for pairing: run ready --format markdown and use the Ready section as the agenda.
  • Track blocked work: use set-deps to declare blockers and blocked to inspect waiting items.
  • Bulk-import a snapshot to reset state during a large replan using import-plan --replace.

FAQ

How do I publish changes so downstream systems see them?

After any mutation command the script prints an update_plan: {...} payload line; parse and publish that payload in the same turn. If missing, run emit-update-plan to regenerate it.

Can I hand-edit the JSONL file to fix a typo?

No. Do not hand-edit existing JSONL lines. Use mutation commands or import-plan --replace to produce canonical, compacted writes.

What happens if a dependency cycle is introduced?

The CLI enforces dependency integrity and rejects cycles, self-deps, and missing IDs at mutation time.