Skip to content

Latest commit

 

History

History
503 lines (358 loc) · 24.3 KB

File metadata and controls

503 lines (358 loc) · 24.3 KB

kspec Agent Instructions

This file is auto-generated from kspec meta. Include it in your AGENTS.md or similar agent instruction file.

Conventions

These are the project's agreed-upon conventions. Follow them in all contributions to maintain consistency.

commits

  • Use conventional commit format (feat, fix, docs, refactor, test, chore)
  • Reference task in commit body when applicable
  • Keep subject line under 72 characters
  • Include Co-Authored-By for AI contributions

Examples:

  • Good: feat: add user login flow — Bad: Added login
  • Good: fix(auth): handle expired tokens — Bad: fixed bug

notes

  • Add notes when completing significant work
  • Include what was done, approach taken, and why
  • Note any deviations from plan or unexpected findings
  • Keep notes concise but informative for future context
  • Before resubmitting after a fix cycle, add a note summarizing what changed and why — this becomes a key activity timeline entry for reviewers

Examples:

  • Good: "Implemented retry logic with exponential backoff. Chose 3 retries max based on API rate limits."
  • Bad: "Done"

naming

  • Use kebab-case for slugs (task-user-login, not taskUserLogin)
  • Prefix task slugs with 'task-' for clarity
  • Use descriptive names that indicate purpose
  • Keep slugs short but unambiguous

tags

  • Use lowercase tags
  • Standard tags include mvp, post-mvp, bug, feature, infra, design
  • Add domain tags like cli, schema, parser, tasks
  • Limit to 3-5 tags per item for focus

branching

  • Use descriptive branch names that indicate the type and scope of work
  • Use prefixes: feat/ for features, fix/ for bug fixes, refactor/ for refactoring, docs/ for documentation
  • Keep branch names short but meaningful (e.g., feat/user-auth, fix/login-crash)
  • Use kebab-case for branch names
  • Before committing, verify current branch with git branch --show-current; never commit directly to main.
  • For task work (manual or automated), prefer kspec task branch @ref to create or resume the deterministic dispatch-compatible branch (dispatch/task//). This preserves dispatch reviewer and fix-cycle continuity.
  • The dispatch/task/ branch namespace is reserved for task-scoped branches. Do not manually create branches under dispatch/task/ — use kspec task branch to ensure the deterministic naming contract.

documentation

  • Write clear, concise documentation that explains why, not just what
  • Include examples for non-trivial concepts
  • Keep documentation close to code (inline comments for complex logic, README for overview)
  • Update documentation when behavior changes

testing

  • ULIDs use Crockford base32 (excludes I, L, O, U) — invalid ULIDs cause SILENT test failures
  • Use testUlid() helper or kspec util ulid for valid test ULIDs
  • Never use JSON.stringify() for YAML — use template strings or yaml library stringify()
  • Playwright E2E tests excluded from vitest — run separately with npm run test:e2e
  • E2E fixtures are SEPARATE from unit test fixtures — never mix them
  • Use npm run test:shard1/shard2/shard3 for faster local dev runs (~50s vs ~150s). Full suite still required before PR.
  • testUlid(prefix) is deterministic unless you pass a sequence; use testUlids() or explicit sequences when tests need distinct IDs.
  • In tests that run git commit in temp repos, set git config user.name and git config user.email after git init.
  • Always use npm test (or npm run test:shard1/2/3 for faster dev runs) to run tests. Never invoke vitest or npx vitest directly — the test runner script (scripts/test.cjs) performs environment readiness checks before executing.
  • Test runner caches results by content hash (git blob SHAs + unstaged diffs + untracked files + Node version + vitest args). Same content = cache hit, even after commits/rebases. Use --fresh to force a full re-run.
  • Test output is condensed by default: success shows only summary stats, failure shows failed tests with error snippets. Full verbose log path is printed. Use --verbose (or CI=true) for full streaming output.
  • Cache is session-scoped under KSPEC_SESSION_ID for dispatch isolation. Parallel agents get independent caches. --fresh clears only the current session's cache.
  • expect.anything() does not match undefined or null in vitest — use the literal undefined when asserting undefined args
  • vi.spyOn(Class.prototype, 'method') may have empty spy.mock.calls for cross-module ESM calls — use a closure variable to capture args instead of asserting on the spy directly
  • setupTempFixtures() returns a flat dir where tempDir IS the specDir — do not path.join with .kspec/ for session or budget operations
  • Prefer behavioral/integration tests over static source analysis. The no-source-scanning oxlint rule enforces at lint time. Use readTestOutput/readTestOutputSync from tests/helpers/cli.ts for legitimate test output file reads.
  • When tests fail after a code change, evaluate whether the tests are correct before adding workarounds — the test may be exposing a real bug in the change
  • Multi-project test fixtures need a git repo and shadow detection for initContext() to resolve specDir — use setupMultiDirFixtures() or manually init git and create .kspec/ markers
  • Test daemons must register cleanup via vitest's onTestFinished at spawn time, not in the test body. Prefer direct spawn() (see tests/e2e/fixtures/test-base.ts) so the OS reaps the daemon via process group on parent death. If a test must invoke 'kspec serve start --detach' because the CLI command itself is under test, read the PID immediately after the spawn returns and register process.kill(pid, 'SIGTERM') in onTestFinished — never rely on inline cleanup that won't run on assertion failure.
  • Test helpers that drive kspec CLI subprocesses must require an explicit cwd parameter. Never fall back to process.cwd() — a missing cwd is a test bug, not a default. A silent fallback caused a shadow worktree destruction incident on 2026-04-11.
  • Test helpers that spawn subprocesses inheriting process.env must route env through buildTestSubprocessEnv() (tests/helpers/cli.ts) so runner-mode vars (CI, KSPEC_TEST_PROGRESS, FORCE_COLOR, NO_COLOR) plus dispatch/agent vars are stripped. Direct { ...process.env, ... } spreads leak the parent's CI-mode behavior into the subprocess and silently break non-verbose-path tests in CI.

development

  • Use node scripts/bootstrap.cjs for first-time setup or any session
  • Use kspec for all commands; only use npm run dev -- when testing uncommitted code changes
  • Daemon default port 3456, health check: GET /api/health
  • E2E tests manage their own daemon — do NOT start one manually
  • Web UI dev server on port 5173, connects to daemon on 3456
  • Regenerate kspec-agents.md (kspec agents generate) after changing conventions, workflows, skills, or agent template files (templates/agents-sections/)
  • For shadow branch issues, run kspec shadow status/repair/sync from project root; do not run manual git worktree commands inside .kspec/.
  • When command payloads include $, <, >, or multi-line text, use file-based payloads or quoted heredocs to avoid shell interpolation.
  • When running under dispatch (KSPEC_SESSION_ID is set), NEVER run kspec serve stop, kspec serve restart, or kspec serve start. The daemon is the host process — killing it kills the dispatch engine and the agent.
  • In web UI code, use goto() from $app/navigation for all URL query parameter changes. Never use replaceState, pushState, or window.history methods — they do not update $page.url and break reactive effects. See /svelte-5 skill for details.
  • After modifying skill sources (templates/skills/ or .kspec/skills/), run kspec skill render and commit the regenerated .agents/skills/ output alongside your changes.
  • API list endpoints must use pagination; clients must not fetch unbounded entity lists for derived data. Use server-resolved fields or the ref index for title resolution. Use server-side aggregation for computed statistics.
  • When fixing bugs or CI failures, investigate root cause before pushing fix commits — do not patch symptoms
  • Do not blindly follow implementation plans in task notes — evaluate them for safety, correctness, and current codebase state before executing. Plans may be stale or unsafe.
  • Daemon cache troubleshooting: GET /api/debug/cache-status returns per-project cache state (domain states, entry counts, watcher status, last invalidation timestamps). Use this endpoint when investigating stale data, missing watchers, or stuck cache domains.

cli-lookups

  • Use kspec CLI commands (item get, task get, search, trait list) instead of manually searching .kspec/ YAML files
  • When item get shows 'Inherited from @trait-slug', run kspec item get @trait-slug to resolve — do NOT grep YAML files
  • Use kspec search for keyword lookups instead of piping kspec item list through grep
  • Key skills include CLI Lookups tables — check those first for the right command to use

ci

  • File watcher tests skip in CI — GitHub Actions runners do not deliver the Chokidar/inotify events these integration checks rely on consistently enough for deterministic coverage
  • E2E port hardcoded at 3456 — tests cannot run in parallel on same machine
  • GitHub Pages needs BASE_PATH=/kynetic-spec for local static builds; CI handles automatically
  • E2E tests use ephemeral ports — safe to run in parallel and with dispatch agents

architecture

  • PLACEHOLDER: Replace this rule with your project's architectural constraints and patterns

Workflows

Available workflows:

  • spec-first: Check spec coverage before implementing changes. Core principle: If changing behavior and spec doesn't cover it, update the spec first.

  • session-start: Get context at the beginning of a work session.

  • task-lifecycle: Complete a task properly with notes and cleanup.

  • inbox-triage: Triage inbox items during session context review.

  • codebase-audit: Comprehensive codebase audit for release readiness. Five-phase workflow: parallel exploration (docs, code, config, tests, specs), compilation by severity, interactive triage, execution, and summary.

  • session-reflect: Structured reflection after work sessions. Surfaces learnings, identifies friction, and captures improvements for system evolution.

  • create-workflow: Meta-workflow for creating new workflows. Ensures consistent structure and matching skill integration.

  • session-reflect-loop: Autonomous reflection for loop mode. High-confidence captures only. MUST search existing before capturing. No user interaction.

  • spec-plan-design: Research and design phase for plan-to-spec translation. Explore codebase, clarify requirements, design approach, review for completeness and spec gaps. Concludes with choosing import or manual execution path.

  • spec-plan-import: Execute plan via structured document import - write document, preview import, import as a durable plan record, iterate with --into, approve, derive, validate, and start work. Follows @spec-plan-design.

  • spec-plan-manual: Execute plan via incremental spec creation - create plan record, find parent, create specs with AC, review traits, derive tasks with plan linking, validate, start work. Follows @spec-plan-design.

Use kspec workflow start @workflow-id to start a workflow.

Quick Start

# First time setup
kspec init            # Initialize kspec in the project
kspec setup           # Configure agent environment

# Returning to work
kspec session start   # Get session context

Verify shadow branch health with kspec shadow status if you encounter issues.

Essential Rules

  1. Use CLI, not manual YAML edits — Never manually edit files in .kspec/. CLI auto-commits to shadow branch.
  2. Spec before code — If changing behavior, check spec coverage. Update spec first if needed.
  3. Add notes — Document what you do in task notes for audit trail.
  4. Check dependencies — Tasks have depends_on relationships; complete prerequisites first.
  5. Always confirm — Ask before creating or modifying spec items.
  6. Batch mutations — Use kspec batch for 2+ sequential write operations (one atomic commit).
  7. Regenerate agent instructions — Run kspec agents generate after changing conventions, workflows, or skills. These are the inputs to kspec-agents.md.
  8. Edit skill sources, not rendered output — Do not edit .agents/skills/ directly. Core skills live in templates/skills/ (+ templates/skills/manifest.yaml), while project/local skills live in .kspec/skills/. Regenerate rendered files with kspec skill render/kspec setup.

Shadow Branch Architecture

.kspec/ is NOT a regular directory — it's a git worktree on an orphan branch (kspec-meta).

.kspec/.git → file pointing to worktree
  ↓
gitdir: .git/worktrees/-kspec
  ↓
Shadow branch (kspec-meta): orphan branch with spec/task files

Why: Spec/task changes don't clutter main branch history. Code PRs and spec changes tracked independently.

How it works: Every kspec command auto-commits to kspec-meta. Auto-pushes to remote if tracking configured. Main branch gitignores .kspec/.

CRITICAL: Always run kspec from project root, never from inside .kspec/. If you see "Cannot run kspec from inside .kspec/ directory", check pwd.

Shadow Branch Commands

kspec shadow status   # Verify health
kspec shadow repair   # Fix broken worktree
kspec shadow sync     # Sync with remote

Troubleshooting

Issue Fix
.kspec/ doesn't exist kspec init
Worktree disconnected kspec shadow repair
Sync conflicts kspec shadow resolve
Commands seem broken Check pwd — must be project root

Task Lifecycle

Key Concepts

Every item has a ULID (canonical) and slug (human-friendly). References use @ prefix: @task-slug or @01JHNKAB.

Spec items (.kspec/modules/*.yaml): Define WHAT to build Tasks (.kspec/project.tasks.yaml): Track the WORK of building

Tasks reference specs via spec_ref. They don't duplicate spec content.

Task States

pending → in_progress → pending_review → completed
              ↓              ↓
          blocked ←──────────┘
              ↓          needs_work
          cancelled     (fix cycle: → in_progress → pending_review)

See kspec help task for transition commands and options.

Terminal States and Reset

completed and cancelled are terminal — no direct transitions out. To change a terminal task's state, reset it first (returns to pending), then transition normally. Use kspec batch for atomic multi-step transitions:

[
  { "command": "task reset", "args": { "ref": "@task-slug" } },
  { "command": "task cancel", "args": { "ref": "@task-slug", "reason": "..." } }
]

blocked is semi-terminalunblock restores the prior state automatically (no reset needed).

Transition commands enforce allowed source states. Use kspec help task to see which commands accept which states.

Spec-First Development

Core principle: If you're changing behavior and the spec doesn't cover it, update the spec first.

Situation Flow
Clear behavior change Check spec → Update/create spec → Derive task
Vague idea, unclear scope Capture in inbox → Triage later
Infra/internal (no user impact) Create task directly, no spec needed
Bug revealing spec gap Fix bug → Update spec to match reality

Creating Work

  • User asks to create a taskkspec task add — always create a task when explicitly asked
  • Clear scope? → Create task directly
  • Unclear scope, no specific guidance?kspec inbox add "idea" → triage later with /kspec:triage
  • Learning/friction?kspec meta observe friction "..." → review during reflection

Rule: When the user says "create a task", always create a task. Inbox-first is fine for your own uncertain ideas — but explicit user requests override that default.

Staying Aligned During Work

Watch for scope expansion:

  • Modifying files outside your current task
  • Adding functionality the spec doesn't mention
  • "While I'm here, I should also..." thoughts

When you notice something outside your task: Capture it separately (inbox item, new task, or observation). Add a note to your current task documenting what you found. Don't fix it inline — even small detours compound into drift. Stay on your task.

Work and Review Lifecycle

Before submitting work for review: kspec task submit @ref (transitions to pending_review).

The full lifecycle:

  1. Work — Implement, test, annotate ACs. See the kspec task-work skill.
  2. Submitkspec task submit @ref signals work is ready for review.
  3. Review — Reviewer creates a kspec review record, investigates, submits verdict. See the kspec review skill.
  4. Merge — After review approval, merge to integration branch. See the kspec merge skill.

Review gates (from kspec review disposition):

  • Review disposition = approved
  • All required checks passing
  • No unresolved blocker threads
  • AC coverage verified (own + trait)

After merge: kspec task complete @ref --reason "Merged. Summary..."

Fix cycle: If review requests changes, task transitions to needs_work. Worker reads review threads via kspec review for-task @ref, addresses blockers, resubmits.

Commit Convention

feat: Feature description

Task: @task-slug
Spec: @spec-ref

Trailers enable kspec log @ref to find commits by task or spec.

Code Annotations

Link tests to acceptance criteria using language-appropriate comment syntax:

// AC: @spec-item ac-N
it('should validate input', () => { ... });
# AC: @spec-item ac-N
def test_validates_input():
    ...

Every AC SHOULD have at least one test with this annotation.

N/A Trait ACs

When a trait AC doesn't apply to a specific spec, annotate it as N/A with a reason:

// AC: @trait-slug ac-N — N/A: reason why it doesn't apply
# AC: @trait-slug ac-N — N/A: reason why it doesn't apply

Group N/A annotations together in a dedicated test or at the top of the test file. The AC: annotation marker with language-appropriate comment prefix is required — do not use prose comments or bullet lists. The annotation must be machine-parseable.

Agent Dispatch Mode

When running as an automated agent via the dispatch engine:

Dispatch Engine Commands

# Start background dispatch (daemon must be running)
kspec agent dispatch start

# Inspect active/queued work and loaded agents
kspec agent dispatch status

# Stream live text output from running invocations
kspec agent dispatch watch

# Stop dispatch gracefully
kspec agent dispatch stop

Built-In Agents

kspec setup ensures default worker/reviewer agent definitions exist in kynetic.meta.yaml:

  • task-worker — handles automation-eligible task.ready, task.in_progress, and task.needs_work
  • pr-reviewer — handles task.pending_review (review and local merge)

Inspect current definitions with:

kspec agent list

Dispatch Rules and Trigger Events

Trigger event Typical handler Notes
task.ready task-worker Worker picks up newly ready automation-eligible tasks
task.in_progress task-worker Worker can continue existing automation-eligible tasks
task.needs_work task-worker Fix-cycle tasks return to worker
task.pending_review pr-reviewer Review and local merge in separate invocation

One-Shot Invocation

Run a single agent directly (outside dispatch):

kspec agent run <agent-id> [prompt]

Common flags:

  • --task @task-ref to target a specific task
  • --dry-run to preview prompt without spawning
  • --json for structured output
  • --timeout <minutes> and --budget <n> for execution limits

Dispatch Loop Behavior

for each dispatched invocation:
  1. Agent runtime checks eligible tasks — if none, invocation ends
  2. Agent works on tasks
     - Before editing files, use `kspec task branch @ref` for the deterministic
       dispatch-compatible branch (dispatch/task/<slug>/<short-id>)
  3. Agent submits task (kspec task submit @ref) when work is complete
  4. Agent stops responding (turn complete)
  5. Reviewer agent picks up pending_review tasks: creates kspec review,
     investigates, submits verdict, merges locally if approved
  6. Continue

Do NOT create GitHub PRs for dispatched work. Agent work is reviewed via kspec review records and merged locally to the integration branch. GitHub PRs are a human-directed activity for merging feature groups into main.

When you stop responding, the dispatch engine continues automatically. Do NOT call kspec agent end-loop after submitting a task.

Task Inheritance

Priority: needs_work > in_progress > pending. Always inherit existing work before starting new tasks. (pending_review tasks are handled by the reviewer agent, not the worker.)

Blocking Rules

Block only for genuine external blockers:

  • Requires human architectural decision
  • Needs spec clarification
  • Depends on external API/service not available
  • Formally blocked by depends_on

Do NOT block for:

  • Task seems complex (do the work)
  • Tests are failing (fix them)
  • Service needs running (start it)
  • Another task is in review (not a formal dependency)
  • Merge conflicts that you can resolve (resolve them — see /kspec:merge skill conflict handling)

After blocking a task:

kspec task block @task --reason "Reason..."
kspec tasks ready --eligible
# If tasks returned: work on next one
# If empty: stop responding — dispatch engine auto-exits

One blocked task is NOT "no more work." kspec tasks ready --eligible output is authoritative.

Batch Usage

Use kspec batch for 2+ sequential write operations — one atomic shadow branch commit instead of N.

JSON Format

Pipe a JSON array of command objects:

[
  { "command": "task set", "args": { "ref": "@task-slug", "automation": "eligible" } },
  {
    "command": "task note",
    "args": { "ref": "@task-slug", "message": "Assessed and marked eligible" }
  },
  { "command": "inbox add", "args": { "text": "New idea to triage", "tag": ["mvp", "cli"] } }
]

Each object has:

  • command — command path without kspec (e.g. "task add", "item ac add")
  • args — object mapping parameter names to values
  • id — optional correlation label for error messages

Argument Rules

Type Key format Example
Positional (<ref>) Parameter name from signature "ref": "@task-slug"
Option (--spec-ref) camelCase or kebab, no -- "specRef": "@spec" or "spec-ref": "@spec"
Boolean flag (--force) Flag name, no -- "force": true
Repeatable (--tag) Same key with array value "tag": ["cli", "bug"]

Boolean true emits the flag; false omits it. Arrays repeat the flag: --tag cli --tag bug.

Invocation

echo '[...]' | kspec batch              # stdin (default)
kspec batch --file commands.json        # from file
kspec batch --commands '[...]'          # inline JSON
kspec batch --dry-run                   # validate without executing
kspec batch --continue                  # don't stop on first error

Discovering Commands

kspec batch commands                    # list all allowed commands
kspec batch commands "task set"         # single command schema
kspec batch commands "task set" --json  # structured output for programmatic use

Quote multi-word command paths: "task set", "item ac add", "meta observe".