Skip to main content

Architecture Overview

Overall Architecture

┌──────────────────────────────────────────────────────────────┐
│                             User                             │
└─────────────────────────────┬────────────────────────────────┘


┌──────────────────────────────────────────────────────────────┐
│  Claude Code / Cursor / OpenCode / Codex / Kiro / Gemini /   │
│  Qoder / CodeBuddy / Copilot / Droid / Kilo / Antigravity /  │
│  Windsurf  +  .agents/skills/ ecosystem (Amp, Cline, …)      │
│               (AI Coding Assistant Interface)                │
└─────────────────────────────┬────────────────────────────────┘

          ┌───────────────────┼──────────────────┐
          │                   │                  │
          ▼                   ▼                  ▼
  ┌───────────────┐  ┌──────────────────┐  ┌─────────────────┐
  │  Commands     │  │  Skills          │  │  Hooks          │
  │  /trellis:*   │  │  (auto-trigger)  │  │  (hook-capable) │
  │               │  │                  │  │                 │
  │  start        │  │  brainstorm      │  │  SessionStart   │
  │  finish-work  │  │  before-dev      │  │  PreToolUse     │
  │  continue     │  │  check           │  │  UserPrompt     │
  │               │  │  update-spec     │  │                 │
  │  [all]        │  │  break-loop      │  │  [see §2.2]     │
  └───────┬───────┘  └────────┬─────────┘  └────────┬────────┘
          │                   │                      │
          └───────────────────┼──────────────────────┘


      ┌──────────────────────────────────────────────────────┐
      │                 .trellis/ Directory                  │
      │                                                      │
      │  spec/        workspace/      tasks/      scripts/   │
      │  (Specs)      (Journals)      (Tasks)     (Python)   │
      └─────────────────────────┬────────────────────────────┘


      ┌──────────────────────────────────────────────────────┐
      │                    Sub-agent System                  │
      │                                                      │
      │   trellis-research → trellis-implement → trellis-check│
      │                                                      │
      │   Each sub-agent receives precise context via JSONL  │
      └─────────────────────────┬────────────────────────────┘


      ┌──────────────────────────────────────────────────────┐
      │                  Your Project Code                   │
      │        (AI generates/modifies code per specs)        │
      └──────────────────────────────────────────────────────┘

workflow.md: the single source of truth

.trellis/workflow.md is the one file that defines the Plan / Execute / Finish contract — Phase 1 (1.0 task.py create → 1.4 task.py start), Phase 2 (2.1 trellis-implement → 2.2 trellis-check), Phase 3 (3.1 final check → 3.4 /trellis:finish-work). Every other piece of the system pulls from it:
  • SessionStart hook auto-injects its TOC + step-level details so AI knows the contract before you type anything.
  • /trellis:continue reads .current-task + task status, then consults workflow.md to figure out which step the task is on and what the next action should be.
  • Skills and sub-agents receive it via JSONL (workflow.md is the first entry in the default implement.jsonl).
  • Task state — default statuses planning / in_progress / completed (set automatically by task.py create / start / archive) map one-to-one to the three phases in workflow.md. workflow.md has per-status reminder blocks; add custom statuses there when you need more states.
Edit workflow.md to change the workflow for your project; every platform, skill, sub-agent, and command re-reads it on the next session. There is no other place where the workflow is hard-coded.

Session Startup Flow

SessionStart hook fires automatically, so the platform-specific session-start.py / session-start.js injects Trellis context at every session open with no manual step. Describe your task directly; optionally run /trellis:start for an explicit context report.
When /trellis:start runs (or when a SessionStart hook fires automatically), here’s what happens:
/trellis:start


┌────────────────────────────────────────┐
│  Hook or command body:                 │
│                                        │
│  Read .trellis/.developer    → identity│
│  Read .trellis/workflow.md   → workflow│
│  Read workspace/{name}/index → history │
│  Read git log               → commits  │
│  Read .trellis/tasks/        → tasks   │
└───────────────────┬────────────────────┘


         ┌──────────────────────────┐
         │  Context injected into AI│
         └────────────┬─────────────┘


      ┌──────────────────────────────────┐
      │  start.md command runs:          │
      │                                  │
      │  Step 1: Read workflow.md        │
      │  Step 2: Run get_context.py      │
      │  Step 3: Read spec indexes       │
      │  Step 4: Report & ask user       │
      └──────────────────────────────────┘

Spec Injection Mechanism

Automatic sub-agent spec injection relies on the platform’s PreToolUse hook (or equivalent). Claude Code, Cursor, OpenCode, CodeBuddy, and Droid support this today. On the other platforms, the main session reads the JSONL files itself and passes the relevant content into sub-agent prompts.
inject-subagent-context (Python on Claude Code, JS on OpenCode) is the core spec-injection engine. When the main session spawns a trellis-* sub-agent, this hook intercepts the call and injects the right JSONL-specified context. Workflow:
Main session spawns: Task(subagent_type="trellis-implement", prompt="...")


┌──────────────────────────────────────────────────────────────┐
│  Hook: inject-subagent-context  (runs BEFORE sub-agent)      │
│                                                              │
│  The HOOK (not the sub-agent) does the reading:              │
│                                                              │
│  1. Hook reads .trellis/.current-task                        │
│     → current task directory path                            │
│                                                              │
│  2. Hook reads {task_dir}/implement.jsonl                    │
│     → list of spec files this sub-agent needs                │
│                                                              │
│  3. Hook reads each file referenced in the JSONL             │
│     → .trellis/spec/backend/index.md                         │
│     → .trellis/spec/backend/database-guidelines.md           │
│     → ...                                                    │
│                                                              │
│  4. Hook reads prd.md (requirements) and info.md (design)    │
│                                                              │
│  5. Hook concatenates everything and prepends it to the      │
│     sub-agent's prompt as "additionalContext"                │
└───────────────────────┬──────────────────────────────────────┘


The sub-agent wakes up with this already in its prompt
(it does not read any of the files itself):

  # trellis-implement Task
  ## Your Context
  === .trellis/spec/backend/index.md ===
  (full content injected by hook)
  === .trellis/spec/backend/database-guidelines.md ===
  (full content injected by hook)
  === {task_dir}/prd.md (Requirements) ===
  (full content injected by hook)
  ## Your Task
  Implement the feature

JSONL Configuration Format

JSONL (JSON Lines) files tell the hook which files to inject into each sub-agent’s prompt. Each line is a JSON object:
{"file": ".trellis/workflow.md", "reason": "Project workflow and conventions"}
{"file": ".trellis/spec/backend/index.md", "reason": "Backend development guide"}
{"file": "src/services/auth.ts", "reason": "Existing auth implementation to align with"}
{"file": ".trellis/tasks/02-27-user-login/research/", "type": "directory", "reason": "Research findings"}
Field descriptions:
FieldRequiredDescription
fileYesRelative path to file or directory (relative to project root)
reasonYesWhy this file is needed
typeNoDefaults to "file". In file mode the hook reads the referenced file as-is regardless of extension (source code, JSON, etc. all work). In "directory" mode the hook only picks up .md files inside, sorted by filename, max 20 — non-.md files are skipped.
What to put in JSONL depends on what the sub-agent needs to execute the task:
  • Specs and workflow: .trellis/workflow.md, .trellis/spec/**/index.md, specific guideline files — shape how the sub-agent writes code.
  • Existing code as reference: a single source file (src/services/auth.ts) is useful when the sub-agent should align with an existing pattern. Prefer single-file entries; directory mode won’t pick up .ts / .py / etc.
  • Research findings: {task_dir}/research/ in directory mode pulls in every .md produced by trellis-research.
Three types of JSONL files:
FileUsed ByTypical Content
implement.jsonltrellis-implementworkflow.md + relevant specs + code pattern examples
check.jsonltrellis-checkquality checklist specs + test / lint rules
research.jsonltrellis-researchproject structure overview + investigation targets
Practical example (implement.jsonl for a backend task, after brainstorm adds context):
{"file": ".trellis/workflow.md", "reason": "Project workflow and conventions"}
{"file": ".trellis/spec/backend/index.md", "reason": "Backend development guide"}
{"file": ".trellis/spec/backend/database-guidelines.md", "reason": "DB patterns used by this task"}
{"file": ".trellis/tasks/02-27-user-login/research/", "type": "directory", "reason": "Research findings from trellis-research"}
Entries after the first two are task-specific and typically added with task.py add-context. Injection behavior per sub-agent:
  • trellis-implement: injects implement.jsonl + prd.md + info.md
  • trellis-check: injects check.jsonl + prd.md (to understand intent)
  • trellis-research: injects project structure overview + research.jsonl (optional)

Sub-agent System

Trellis ships three sub-agents, each with a focused role, explicit restrictions, and a JSONL spec injection lane:
Sub-agentRoleRestrictionPrimary context
trellis-researchCodebase / doc searchRead-onlyresearch.jsonl
trellis-implementWriting codeForbidden from git commitimplement.jsonl + prd.md
trellis-checkVerify + self-fixWrites code only to fixcheck.jsonl + prd.md
Typical task flow in the main session:
trellis-brainstorm skill

  │  Clarify scope, draft prd.md, create task directory + JSONL config
  │  Spawn trellis-research sub-agent when investigation is needed


trellis-before-dev skill

  │  Read relevant spec files before coding starts


Spawn trellis-implement sub-agent

  │  Hook injects implement.jsonl context
  │  Sub-agent writes the code, does not git commit


Spawn trellis-check sub-agent

  │  Hook injects check.jsonl context
  │  Runs lint / typecheck / test, compares diff vs. quality checklist
  │  Self-fixes within its internal retry loop


/trellis:finish-work

  │  Human validates + commits, then finish-work archives the task
  │  and appends a session entry to the workspace journal