> ## Documentation Index
> Fetch the complete documentation index at: https://docs.trytrellis.app/llms.txt
> Use this file to discover all available pages before exploring further.

# v0.5.0-beta.12

> 2026-04-23

Phase 1.3 is now agent-curated. `task.py init-context` is removed; `task.py create` seeds `implement.jsonl` / `check.jsonl` with a self-describing `_example` line on sub-agent-capable platforms, and the AI fills real spec + research entries per `workflow.md` Phase 1.3. Session-start READY gate across four implementations now requires at least one curated entry. Skill Routing tables split per-platform. Release pipeline hardened. Not breaking; `trellis update` handles existing tasks transparently.

## Feature Changes

### workflow\.md Phase 1.3 is now filled in by the agent, not by a script with pre-generated defaults

The old `task.py init-context` pre-filled `implement.jsonl` / `check.jsonl` from `dev_type` + package config, assuming the template path `spec/<package>/{backend,frontend}/index.md`. Monorepos that split by language (e.g. `package = backend` + `package = frontend`) produced entries pointing at files that don't exist — which then led the agent to pre-fill the jsonl itself, and the many tool-call rounds that followed scattered the model's attention and drifted it off the Trellis workflow.

Seed row format (one line per jsonl, no `file` field so every consumer skips it):

```jsonl theme={null}
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line when done."}
```

### Skill Routing tables split per-platform

`workflow.md` Skill Routing and DO-NOT-skip tables now have two dispatch modes: IDEs/CLIs that support sub-agents invoke `trellis-implement` to do the actual coding, while platforms without sub-agents load `trellis-before-dev` in the main agent and code there directly.

| Sub-agent platforms                                                                      | Non-sub-agent platforms                             |
| ---------------------------------------------------------------------------------------- | --------------------------------------------------- |
| Claude / Cursor / OpenCode / Codex / Kiro / Gemini / Qoder / CodeBuddy / Copilot / Droid | Kilo / Antigravity / Windsurf                       |
| Dispatch `trellis-implement` sub-agent per Phase 2.1                                     | Load `trellis-before-dev` skill (main-session flow) |

### Session-start READY gate across four implementations

Before this release, all four session-start implementations treated `implement.jsonl` file existence as "ready for Phase 2". After `task.py create` seeded jsonl, the breadcrumb jumped straight to `Status: READY` and the AI skipped Phase 1.3 curation.

Now each implementation scans the jsonl for at least one row with a `file` key. Seed-only jsonl surfaces as `Status: PLANNING (Phase 1.3)` with a Next-Action pointing at the curation step.

```python theme={null}
def _has_curated_jsonl_entry(jsonl_path: Path) -> bool:
    """A freshly seeded jsonl only contains `{"_example": ...}` — that is NOT ready."""
    for line in jsonl_path.read_text(encoding="utf-8").splitlines():
        line = line.strip()
        if not line:
            continue
        try:
            row = json.loads(line)
        except json.JSONDecodeError:
            continue
        if isinstance(row, dict) and row.get("file"):
            return True
    return False
```

| Implementation                      | Consumed by                                           |
| ----------------------------------- | ----------------------------------------------------- |
| `shared-hooks/session-start.py`     | Claude, Cursor, Kiro, CodeBuddy, Droid, Gemini, Qoder |
| `codex/hooks/session-start.py`      | Codex                                                 |
| `copilot/hooks/session-start.py`    | Copilot                                               |
| `opencode/plugins/session-start.js` | OpenCode (JS plugin runtime)                          |

### Hook + prelude tolerance for seed-only jsonl

`shared-hooks/inject-subagent-context.py:read_jsonl_entries` filters rows without `file` silently (no error) but emits a single stderr warning when the result is empty.

`configurators/shared.ts:buildPullBasedPrelude` teaches Class-2 sub-agents (Codex / Copilot / Gemini / Qoder) to skip rows without `file` and fall back to `prd.md` + self-discovered specs when the jsonl has only the seed row.

## Internal Improvements

### Pre-release manifest continuity guard

`packages/cli/scripts/check-manifest-continuity.js` queries `npm view @mindfoldhq/trellis versions --json` and diffs against local `src/migrations/manifests/*.json`. Any version on npm without a corresponding local manifest fails the check non-zero.

Background: `trellis update` applies migrations where `v > installed && v <= current`. A version on npm without its local manifest silently skips its migration bucket for users upgrading from adjacent versions — see the beta.10 incident in `.trellis/spec/cli/backend/migrations.md`.

| Release script                                    | Pre-flight order                                                                      |
| ------------------------------------------------- | ------------------------------------------------------------------------------------- |
| `release` / `release:minor` / `release:major`     | `check-manifest-continuity.js` → `pnpm test` → bump → commit → tag → push             |
| `release:beta` / `release:rc` / `release:promote` | `check-manifest-continuity.js` → `check-docs-changelog.js` → `pnpm test` → bump → ... |

Historical gaps frozen in `KNOWN_GAPS` (pre-manifest-system versions 0.1.0–0.1.8, 0.2.1–0.2.11; early public prerelease 0.3.10-beta.0). The comment block documents the list must not be extended — any new gap means root-cause fix, not whitelist append.

Emergency bypass: `SKIP_MANIFEST_CONTINUITY=1 pnpm release:beta`. Prints a loud banner when set.

### `trellis update` backup-phase stack-overflow fix

`createFullBackup()` descended into old `.trellis/.backup-*` directories during `.trellis/` scan, and those old backups in turn contained nested `.opencode/node_modules` (tens of thousands of files). The original `collectAllFiles()` used recursion + `files.push(...largeArray)`, which tripped V8's `Maximum call stack size exceeded` on large file counts. `trellis update` crashed at the backup phase after the user confirmed.

| Fix                                                                                                                                                                               | Location                                  |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
| `collectAllFiles` rewritten as iterative stack traversal (no recursion, no large-array spread)                                                                                    | `packages/cli/src/commands/update.ts:770` |
| Skip `node_modules`, `.backup-*`, and other excluded dirs at the scan phase, not only at the copy phase                                                                           | `packages/cli/src/commands/update.ts:683` |
| Normalize backslashes to forward slashes before matching `BACKUP_EXCLUDE_PATTERNS` (aligns with `isManagedPath`'s existing regex). `.claude\worktrees\...` now matches on Windows | `packages/cli/src/commands/update.ts:689` |
| `collectAllFiles` skips symlinks and Windows NTFS junctions (`isSymbolicLink()` returns true for junctions too), preventing infinite scans on cyclic paths                        | `packages/cli/src/commands/update.ts:787` |
| Print full stack trace when `DEBUG=1` or `TRELLIS_DEBUG=1` is set                                                                                                                 | `packages/cli/src/cli/index.ts:130`       |

Regression coverage added in `test/commands/update-internals.test.ts` and `test/commands/update.integration.test.ts`.

Temporary workaround for users on a pre-fix published CLI: `rm -rf .trellis/.backup-*` drops the old backups; subsequent `trellis update` runs won't hit the overflow source.

### `create-manifest.js` guards against rewriting published manifests

The script now refuses to (re)write a manifest for a version already on npm — even with `force: true`. Interactive mode adds the npm-published check before the existing local-file overwrite prompt.

```
$ node scripts/create-manifest.js --stdin <<< '{"version": "0.5.0-beta.11", ...}'
✗ Version 0.5.0-beta.11 is already published on npm.
  Its manifest is part of the update contract and must NOT be rewritten.
  If you need to release additional migrations, use the NEXT version number.
```

### `vi.mock("node:child_process")` now returns a valid Python version string

`update.integration.test.ts` and `init-joiner.integration.test.ts` stubbed `execSync` to return empty string for all commands. `init()` invokes `requireSupportedPython()` which calls `execSync("python3 --version")` and treats empty output as "Python not found", throwing before any test assertion ran.

```typescript theme={null}
// Before — blanket empty return:
vi.mock("node:child_process", () => ({
  execSync: vi.fn().mockReturnValue(""),
}));

// After — conditional return for python version probe:
vi.mock("node:child_process", () => ({
  execSync: vi.fn().mockImplementation((cmd: string) => {
    const py = process.platform === "win32" ? "python" : "python3";
    return cmd === `${py} --version` ? "Python 3.11.12" : "";
  }),
}));
```

Resolves 36 pre-existing failures. Full suite: 664/664 green.

## Upgrade

Existing projects:

```bash theme={null}
trellis update
```

Picks up the updated scripts + hooks. Existing `implement.jsonl` / `check.jsonl` files keep working — seed rows without `file` are ignored by every consumer. If your prior `init-context`-generated jsonl points at paths that don't exist on your monorepo spec layout (typical for `package = backend | frontend` projects), re-curate per `workflow.md` Phase 1.3:

```bash theme={null}
python3 ./.trellis/scripts/get_context.py --mode packages       # see what specs exist
python3 ./.trellis/scripts/task.py add-context <task-dir> implement \
  ".trellis/spec/<pkg>/<layer>/index.md" "why it applies"
```

After first real entry, the session-start breadcrumb flips from `PLANNING (Phase 1.3)` to `READY`.

Fresh install:

```bash theme={null}
npm i -g @mindfoldhq/trellis@0.5.0-beta.12
```
