@blulotus/trellis 0.7.2 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/configurators/workflow.d.ts +15 -0
- package/dist/configurators/workflow.d.ts.map +1 -1
- package/dist/configurators/workflow.js +77 -7
- package/dist/configurators/workflow.js.map +1 -1
- package/dist/templates/claude/agents/trellis-research.md +10 -0
- package/dist/templates/codex/agents/trellis-research.toml +17 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-skills-or-commands.md +18 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-spec-structure.md +1 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-workflow.md +1 -0
- package/dist/templates/common/skills/brainstorm.md +30 -0
- package/dist/templates/common/skills/check.md +22 -1
- package/dist/templates/common/skills/tdd.md +4 -0
- package/dist/templates/common/skills/update-spec.md +24 -0
- package/dist/templates/markdown/index.d.ts +1 -0
- package/dist/templates/markdown/index.d.ts.map +1 -1
- package/dist/templates/markdown/index.js +2 -0
- package/dist/templates/markdown/index.js.map +1 -1
- package/dist/templates/markdown/spec/backend/index.md.txt +29 -0
- package/dist/templates/markdown/spec/frontend/index.md.txt +33 -0
- package/dist/templates/markdown/spec/frontend/visual-design.md.txt +155 -0
- package/dist/templates/trellis/config.yaml +24 -0
- package/dist/templates/trellis/workflow.md +2 -0
- package/package.json +2 -2
|
@@ -1,4 +1,19 @@
|
|
|
1
1
|
import { type ProjectType, type DetectedPackage } from "../utils/project-detector.js";
|
|
2
|
+
/** How `spec/frontend/visual-design.md` is scaffolded. See config.yaml. */
|
|
3
|
+
export type VisualDesignMode = "auto" | "always";
|
|
4
|
+
/**
|
|
5
|
+
* Read `spec.visual_design` from `.trellis/config.yaml`.
|
|
6
|
+
*
|
|
7
|
+
* `createWorkflowStructure` writes config.yaml before it writes spec, and
|
|
8
|
+
* `writeFile` preserves an existing config, so on a re-init this reads the
|
|
9
|
+
* user's own file. A first init has no config yet and gets `auto`.
|
|
10
|
+
*
|
|
11
|
+
* Hand-parsed for the same reason `loadUpdateSkipPaths` in `commands/update.ts`
|
|
12
|
+
* is: config.yaml is read in several places without a YAML dependency.
|
|
13
|
+
*
|
|
14
|
+
* @internal Exported for testing only
|
|
15
|
+
*/
|
|
16
|
+
export declare function loadVisualDesignMode(cwd: string): VisualDesignMode;
|
|
2
17
|
/**
|
|
3
18
|
* Options for creating workflow structure
|
|
4
19
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["../../src/configurators/workflow.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["../../src/configurators/workflow.ts"],"names":[],"mappings":"AAyCA,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,eAAe,EACrB,MAAM,8BAA8B,CAAC;AAOtC,2EAA2E;AAC3E,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEjD;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAyClE;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,yCAAyC;IACzC,WAAW,EAAE,WAAW,CAAC;IACzB,yFAAyF;IACzF,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,kEAAkE;IAClE,QAAQ,CAAC,EAAE,eAAe,EAAE,CAAC;IAC7B,0EAA0E;IAC1E,kBAAkB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACjC;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,IAAI,CAAC,CA0Ef"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
1
2
|
import path from "node:path";
|
|
2
3
|
import { DIR_NAMES, PATHS } from "../constants/paths.js";
|
|
3
4
|
import { copyTrellisDir } from "../templates/extract.js";
|
|
@@ -8,12 +9,65 @@ import { agentProgressIndexContent,
|
|
|
8
9
|
// Backend structure (multi-doc)
|
|
9
10
|
backendIndexContent, backendDirectoryStructureContent, backendDatabaseGuidelinesContent, backendLoggingGuidelinesContent, backendQualityGuidelinesContent, backendErrorHandlingContent,
|
|
10
11
|
// Frontend structure (multi-doc)
|
|
11
|
-
frontendIndexContent, frontendDirectoryStructureContent, frontendTypeSafetyContent, frontendHookGuidelinesContent, frontendComponentGuidelinesContent, frontendQualityGuidelinesContent, frontendStateManagementContent,
|
|
12
|
+
frontendIndexContent, frontendDirectoryStructureContent, frontendTypeSafetyContent, frontendHookGuidelinesContent, frontendComponentGuidelinesContent, frontendQualityGuidelinesContent, frontendStateManagementContent, frontendVisualDesignContent,
|
|
12
13
|
// Guides structure
|
|
13
14
|
guidesIndexContent, guidesCrossLayerThinkingGuideContent, guidesCodeReuseThinkingGuideContent, } from "../templates/markdown/index.js";
|
|
14
15
|
import { writeFile, ensureDir } from "../utils/file-writer.js";
|
|
15
16
|
import { replacePythonCommandLiterals } from "./shared.js";
|
|
16
17
|
import { sanitizePkgName, } from "../utils/project-detector.js";
|
|
18
|
+
/**
|
|
19
|
+
* Read `spec.visual_design` from `.trellis/config.yaml`.
|
|
20
|
+
*
|
|
21
|
+
* `createWorkflowStructure` writes config.yaml before it writes spec, and
|
|
22
|
+
* `writeFile` preserves an existing config, so on a re-init this reads the
|
|
23
|
+
* user's own file. A first init has no config yet and gets `auto`.
|
|
24
|
+
*
|
|
25
|
+
* Hand-parsed for the same reason `loadUpdateSkipPaths` in `commands/update.ts`
|
|
26
|
+
* is: config.yaml is read in several places without a YAML dependency.
|
|
27
|
+
*
|
|
28
|
+
* @internal Exported for testing only
|
|
29
|
+
*/
|
|
30
|
+
export function loadVisualDesignMode(cwd) {
|
|
31
|
+
const configPath = path.join(cwd, DIR_NAMES.WORKFLOW, "config.yaml");
|
|
32
|
+
if (!fs.existsSync(configPath))
|
|
33
|
+
return "auto";
|
|
34
|
+
let raw = null;
|
|
35
|
+
try {
|
|
36
|
+
const lines = fs.readFileSync(configPath, "utf-8").split("\n");
|
|
37
|
+
let inSpec = false;
|
|
38
|
+
for (const line of lines) {
|
|
39
|
+
if (/^spec:\s*(#.*)?$/.test(line)) {
|
|
40
|
+
inSpec = true;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
// A non-indented, non-comment, non-blank line closes the block.
|
|
44
|
+
if (inSpec && /^\S/.test(line) && !line.startsWith("#")) {
|
|
45
|
+
inSpec = false;
|
|
46
|
+
}
|
|
47
|
+
if (!inSpec)
|
|
48
|
+
continue;
|
|
49
|
+
const match = /^\s+visual_design:\s*([^#]+)/.exec(line);
|
|
50
|
+
if (match) {
|
|
51
|
+
raw = match[1]
|
|
52
|
+
.trim()
|
|
53
|
+
.replace(/^['"]|['"]$/g, "")
|
|
54
|
+
.toLowerCase();
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
console.warn(`Warning: failed to read ${configPath}, using spec.visual_design: auto`);
|
|
61
|
+
return "auto";
|
|
62
|
+
}
|
|
63
|
+
if (raw === null || raw === "auto")
|
|
64
|
+
return "auto";
|
|
65
|
+
if (raw === "always")
|
|
66
|
+
return "always";
|
|
67
|
+
console.warn(`Warning: unknown spec.visual_design value "${raw}" in ${configPath}; ` +
|
|
68
|
+
`expected "auto" or "always". Using "auto".`);
|
|
69
|
+
return "auto";
|
|
70
|
+
}
|
|
17
71
|
/**
|
|
18
72
|
* Create workflow structure based on project type
|
|
19
73
|
*
|
|
@@ -33,6 +87,10 @@ export async function createWorkflowStructure(cwd, options) {
|
|
|
33
87
|
const packages = options?.packages;
|
|
34
88
|
const remoteSpecPackages = options?.remoteSpecPackages;
|
|
35
89
|
const workflowMd = options?.workflowMdOverride ?? workflowMdTemplate;
|
|
90
|
+
// Read before this function writes config.yaml. `--force` overwrites the
|
|
91
|
+
// user's config with the template, so reading it later would silently reset
|
|
92
|
+
// the choice to `auto` on exactly the run that rewrites the files.
|
|
93
|
+
const visualDesignMode = loadVisualDesignMode(cwd);
|
|
36
94
|
// Create base .trellis directory
|
|
37
95
|
ensureDir(path.join(cwd, DIR_NAMES.WORKFLOW));
|
|
38
96
|
// Copy scripts/ directory from templates
|
|
@@ -64,11 +122,11 @@ export async function createWorkflowStructure(cwd, options) {
|
|
|
64
122
|
// These are NOT dogfooded - they are generic templates for new projects
|
|
65
123
|
if (packages && packages.length > 0) {
|
|
66
124
|
// Monorepo mode: create per-package spec directories
|
|
67
|
-
await createSpecTemplates(cwd, projectType, packages, remoteSpecPackages);
|
|
125
|
+
await createSpecTemplates(cwd, projectType, visualDesignMode, packages, remoteSpecPackages);
|
|
68
126
|
}
|
|
69
127
|
else if (!skipSpecTemplates) {
|
|
70
128
|
// Single-repo mode: create global spec (skip if using remote template)
|
|
71
|
-
await createSpecTemplates(cwd, projectType);
|
|
129
|
+
await createSpecTemplates(cwd, projectType, visualDesignMode);
|
|
72
130
|
}
|
|
73
131
|
}
|
|
74
132
|
/**
|
|
@@ -118,6 +176,7 @@ async function writeFrontendDocs(specBase) {
|
|
|
118
176
|
content: frontendQualityGuidelinesContent,
|
|
119
177
|
},
|
|
120
178
|
{ name: "state-management.md", content: frontendStateManagementContent },
|
|
179
|
+
{ name: "visual-design.md", content: frontendVisualDesignContent },
|
|
121
180
|
];
|
|
122
181
|
for (const doc of docs) {
|
|
123
182
|
await writeFile(path.join(frontendDir, doc.name), doc.content);
|
|
@@ -126,15 +185,26 @@ async function writeFrontendDocs(specBase) {
|
|
|
126
185
|
/**
|
|
127
186
|
* Write spec docs for a given project type into a target spec directory.
|
|
128
187
|
*/
|
|
129
|
-
async function writeSpecForType(specBase, projectType) {
|
|
188
|
+
async function writeSpecForType(specBase, projectType, visualDesignMode) {
|
|
130
189
|
if (projectType !== "frontend") {
|
|
131
190
|
await writeBackendDocs(specBase);
|
|
132
191
|
}
|
|
133
192
|
if (projectType !== "backend") {
|
|
134
193
|
await writeFrontendDocs(specBase);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (visualDesignMode === "always") {
|
|
197
|
+
// Backend-only layer, but the user asked for the visual craft rules
|
|
198
|
+
// anyway — backend work in this project reaches rendered surfaces. Only
|
|
199
|
+
// this one file: every other `frontend/` doc is an unfilled stub, so
|
|
200
|
+
// creating them would add noise the layer has no use for. The backend
|
|
201
|
+
// index points here whenever the file exists.
|
|
202
|
+
const frontendDir = path.join(specBase, "frontend");
|
|
203
|
+
ensureDir(frontendDir);
|
|
204
|
+
await writeFile(path.join(frontendDir, "visual-design.md"), frontendVisualDesignContent);
|
|
135
205
|
}
|
|
136
206
|
}
|
|
137
|
-
async function createSpecTemplates(cwd, projectType, packages, remoteSpecPackages) {
|
|
207
|
+
async function createSpecTemplates(cwd, projectType, visualDesignMode, packages, remoteSpecPackages) {
|
|
138
208
|
// Ensure spec directory exists
|
|
139
209
|
ensureDir(path.join(cwd, PATHS.SPEC));
|
|
140
210
|
// Guides - always created regardless of mode
|
|
@@ -163,12 +233,12 @@ async function createSpecTemplates(cwd, projectType, packages, remoteSpecPackage
|
|
|
163
233
|
const pkgSpecBase = path.join(cwd, `${PATHS.SPEC}/${dirName}`);
|
|
164
234
|
ensureDir(pkgSpecBase);
|
|
165
235
|
const pkgType = pkg.type === "unknown" ? "fullstack" : pkg.type;
|
|
166
|
-
await writeSpecForType(pkgSpecBase, pkgType);
|
|
236
|
+
await writeSpecForType(pkgSpecBase, pkgType, visualDesignMode);
|
|
167
237
|
}
|
|
168
238
|
}
|
|
169
239
|
else {
|
|
170
240
|
// Single-repo mode
|
|
171
|
-
await writeSpecForType(path.join(cwd, PATHS.SPEC), projectType);
|
|
241
|
+
await writeSpecForType(path.join(cwd, PATHS.SPEC), projectType, visualDesignMode);
|
|
172
242
|
}
|
|
173
243
|
}
|
|
174
244
|
//# sourceMappingURL=workflow.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow.js","sourceRoot":"","sources":["../../src/configurators/workflow.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD,2DAA2D;AAC3D,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,GACb,MAAM,+BAA+B,CAAC;AAEvC,4BAA4B;AAC5B,OAAO,EACL,yBAAyB;AACzB,gCAAgC;AAChC,mBAAmB,EACnB,gCAAgC,EAChC,gCAAgC,EAChC,+BAA+B,EAC/B,+BAA+B,EAC/B,2BAA2B;AAC3B,iCAAiC;AACjC,oBAAoB,EACpB,iCAAiC,EACjC,yBAAyB,EACzB,6BAA6B,EAC7B,kCAAkC,EAClC,gCAAgC,EAChC,8BAA8B;
|
|
1
|
+
{"version":3,"file":"workflow.js","sourceRoot":"","sources":["../../src/configurators/workflow.ts"],"names":[],"mappings":"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"}
|
|
@@ -121,6 +121,16 @@ Each `{TASK_DIR}/research/<topic>.md` should follow:
|
|
|
121
121
|
|
|
122
122
|
## Guidelines
|
|
123
123
|
|
|
124
|
+
### Source Quality
|
|
125
|
+
|
|
126
|
+
Follow every claim back to the source that owns it. Official documentation, a specification, a first-party API reference, and the dependency's own installed source or lockfile own their facts — where the installed source lives is ecosystem-specific (`node_modules/`, `site-packages/`, `vendor/`, the Cargo registry, the Go module cache), so find where this project actually keeps it. A blog post, a forum answer, a recollection, or another project's wrapper around the same library owns nothing; each is a lead pointing at the real source, and the real source is what gets cited.
|
|
127
|
+
|
|
128
|
+
Prefer sources you can open in this repo or on this machine — those are verifiable right now. Reach for the network only when the fact lives nowhere local.
|
|
129
|
+
|
|
130
|
+
Record the version you read against whenever the fact can change between versions. A finding with no version is not reusable next session.
|
|
131
|
+
|
|
132
|
+
Where only a secondary source exists, or the owning source is unreachable from this environment, write that down as a caveat instead of presenting the claim as established.
|
|
133
|
+
|
|
124
134
|
### DO
|
|
125
135
|
|
|
126
136
|
- Provide specific file paths and line numbers
|
|
@@ -46,6 +46,23 @@ through the chat reply is a failure.
|
|
|
46
46
|
5. Reply with only: list of files written, one-line summary per file,
|
|
47
47
|
any critical caveats. Do not paste full research into the reply.
|
|
48
48
|
|
|
49
|
+
## Source quality
|
|
50
|
+
|
|
51
|
+
Follow every claim back to the source that owns it. Official docs, a spec, a
|
|
52
|
+
first-party API reference, and the dependency's own installed source or
|
|
53
|
+
lockfile own their facts — find where this project keeps that source
|
|
54
|
+
(`node_modules/`, `site-packages/`, `vendor/`, the Cargo registry, the Go
|
|
55
|
+
module cache). A blog post, a forum answer, a recollection, or another
|
|
56
|
+
project's wrapper owns nothing; each is a lead, and the real source is what
|
|
57
|
+
gets cited. Prefer sources you can open in this repo or on this machine;
|
|
58
|
+
reach for the network only when the fact lives nowhere local.
|
|
59
|
+
|
|
60
|
+
Record the version you read against whenever the fact can change between
|
|
61
|
+
versions — a finding with no version is not reusable next session. Where only
|
|
62
|
+
a secondary source exists, or the owning source is unreachable from this
|
|
63
|
+
environment, write that down under Caveats instead of presenting the claim as
|
|
64
|
+
established.
|
|
65
|
+
|
|
49
66
|
## Scope limits
|
|
50
67
|
|
|
51
68
|
Write allowed ONLY in `{TASK_DIR}/research/`.
|
|
@@ -62,6 +62,24 @@ The same directory shape is used by two very different ownership models:
|
|
|
62
62
|
|
|
63
63
|
If the goal is "make my project's AI behave differently when discussing release notes," the answer is almost always a project-local skill, not surgery on `trellis-meta/`.
|
|
64
64
|
|
|
65
|
+
## How To Write It
|
|
66
|
+
|
|
67
|
+
The rules below apply to any document an agent consumes — a skill, a command, a workflow, an `AGENTS.md` line, a `.trellis/spec/` file. The packaging differs; the writing does not.
|
|
68
|
+
|
|
69
|
+
**Two budgets, and every addition spends one.** *Context load* is what always-loaded material costs on every turn: a skill description, an `AGENTS.md` line. *Cognitive load* is what it costs the human, who has to remember the thing exists and when to reach for it. Material behind a pointer escapes context load at the price of the pointer's own line. A description is permanent context load in exchange for the agent being able to fire the skill itself — worth paying only when the agent, or another skill, must reach it unprompted.
|
|
70
|
+
|
|
71
|
+
**Disclose by branch.** Rank each piece by how immediately the agent needs it: in-file step (what it does, in order), in-file reference (consulted on demand), then disclosed reference in `references/` behind a pointer. The test is branching: inline what every path needs, push behind a pointer what only some paths reach. A flat set of peer rules all on one rung is a fine arrangement, not a smell. Sprawl is the failure mode — a document too long even when every line is live, because attention thins across the excess.
|
|
72
|
+
|
|
73
|
+
**End every step on a checkable completion criterion.** "Understanding reached" invites stopping early; "every changed file accounted for" does not. How much the criterion demands is what drives the digging the agent does inside the step, so wording it weakly quietly reduces the work performed.
|
|
74
|
+
|
|
75
|
+
**Prefer a word the model already holds.** A compact pretrained concept — *tight* loop, the loop goes *red*, the question *frontier*, a test *seam* — anchors a whole region of behavior in one token, and repeating that token builds a distributed definition. Repeat the word, never the sentence. Coining your own works only if you define it, and you pay in definition tokens what an existing word gives free.
|
|
76
|
+
|
|
77
|
+
**State the target, not the ban.** A prohibition drags the forbidden behavior into context and makes it more available, not less; the negation is a weak modifier over a strongly activated concept. Prefer "keep comments to one line" over "do not write long comments". Reserve a bare prohibition for a hard guardrail that has no positive phrasing, and even then pair it with the positive target.
|
|
78
|
+
|
|
79
|
+
**Delete no-ops.** An instruction the model already follows by default pays load and buys nothing. The test is against the *model's* default, not a reader's expectation — settle a disagreement by running the document, not by arguing. A leading word too weak to beat the default is a no-op too, and the fix is a stronger word rather than a different technique.
|
|
80
|
+
|
|
81
|
+
**Keep one source of truth.** Duplicated meaning costs maintenance and inflates that meaning's apparent rank. The environment is a source of truth as well — `package.json` scripts, config files, `--help` output — so a document restating it is a cache that earns its load only when the lookup is expensive. Cache the unwritten convention and the reason behind a choice; leave one-command lookups to the environment where they cannot go stale.
|
|
82
|
+
|
|
65
83
|
## Modify A Command/Prompt/Workflow
|
|
66
84
|
|
|
67
85
|
Explicit entry points should state:
|
|
@@ -8,6 +8,7 @@ When the user wants to change the engineering conventions AI follows, add new sp
|
|
|
8
8
|
2. `.trellis/spec/`
|
|
9
9
|
3. `.trellis/workflow.md` planning artifact guidance and Phase 3.3
|
|
10
10
|
4. Current task `implement.jsonl` / `check.jsonl`
|
|
11
|
+
5. [`change-skills-or-commands.md`](./change-skills-or-commands.md) → "How To Write It" — spec docs are agent-consumed documents too, so the information-hierarchy, single-source-of-truth, and no-op rules apply to them as written.
|
|
11
12
|
|
|
12
13
|
## Common Needs
|
|
13
14
|
|
|
@@ -7,6 +7,7 @@ When the user wants to change Trellis phases, next-action hints, whether to crea
|
|
|
7
7
|
1. `.trellis/workflow.md`
|
|
8
8
|
2. Entry files for the current platform, such as skills/commands/prompts/workflows
|
|
9
9
|
3. The current task's `task.json` and `prd.md`
|
|
10
|
+
4. [`change-skills-or-commands.md`](./change-skills-or-commands.md) → "How To Write It" — the writing rules apply to every document an agent reads, and `workflow.md` is the one loaded most often. Per-turn breadcrumbs are always-loaded context, so the pruning and no-op rules bite hardest here.
|
|
10
11
|
|
|
11
12
|
## Common Needs And Edit Points
|
|
12
13
|
|
|
@@ -89,6 +89,33 @@ Do not manufacture clarification questions when the request and repository evide
|
|
|
89
89
|
|
|
90
90
|
The final review is a required phase-transition gate, not a prohibited process question. The user's task request, the initial implementation request, and approval given before the latest final summary do not satisfy this gate.
|
|
91
91
|
|
|
92
|
+
## Decisions Prose Cannot Settle
|
|
93
|
+
|
|
94
|
+
Some decisions are neither facts you can look up nor questions a round of prose can settle: what a screen should look like, whether a state model admits a state it should forbid. Listing three options in words leaves the user unable to tell them apart.
|
|
95
|
+
|
|
96
|
+
Climb only as far as the decision needs, and stop at the first rung that settles it.
|
|
97
|
+
|
|
98
|
+
| Rung | Form | Reach for it when |
|
|
99
|
+
|---|---|---|
|
|
100
|
+
| 1 | One line describing the layout or shape | Default |
|
|
101
|
+
| 2 | An ASCII sketch carried inside the round's question, through the host's structured-question tool (Claude Code: `AskUserQuestion`, with the sketch in an option's `preview`; Codex: `request_user_input`) | Two or more arrangements are defensible and they differ structurally |
|
|
102
|
+
| 3 | Build one version, then show the rendered result | Only one arrangement is defensible and what is left is finish |
|
|
103
|
+
| 4 | A throwaway prototype | Rung 2 failed to settle it **and** the user authorised the cost in this turn |
|
|
104
|
+
|
|
105
|
+
Rung 2 carries exactly what drives rework: which region is primary, what sits where, how many zones, the information hierarchy. What it cannot carry — type, colour, motion feel — is the part that is cheap to change once it exists. So a sketch plus one build pass beats three built variants nearly every time.
|
|
106
|
+
|
|
107
|
+
Never climb to rung 4 on your own initiative. Name the decision rung 2 failed to settle, state what the prototype costs, and ask.
|
|
108
|
+
|
|
109
|
+
### Rung 4, once authorised
|
|
110
|
+
|
|
111
|
+
Two shapes, not equally worth their cost.
|
|
112
|
+
|
|
113
|
+
A **logic prototype** answers "can this state exist when it must not" for a state machine, reducer, or data model. One self-contained HTML file: the logic as a pure module touching no DOM, a panel showing full state after every action, one button per action for free play, plus a few ordered scenarios covering the awkward cases. Label everything in the project's domain language so a non-developer can drive it. Cheap, and it pays twice — the validated module lifts into real code, and a model that admits an illegal state costs far more to correct after implementation.
|
|
114
|
+
|
|
115
|
+
A **UI variant prototype** answers "what should this look like" with several structurally different versions behind one URL parameter, switchable in place. Mount them on the real page with its real data and density; variants judged in an empty route all look fine. They must disagree about layout and hierarchy, not colour. Expensive, and since it needs the host page to already exist, rung 3 usually beats it.
|
|
116
|
+
|
|
117
|
+
Either way record the question, the options, and the resolution in `research/prototype-<topic>.md`. Fold the winning decision into real code and keep the prototype itself out of the main branch, pointed at from the task artifact.
|
|
118
|
+
|
|
92
119
|
## Thinking Framework: First Principles Analysis
|
|
93
120
|
|
|
94
121
|
When requirements are vague, solutions feel over-engineered, or you're about to add complexity "because everyone does" — decompose to fundamental truths before reasoning upward.
|
|
@@ -157,9 +184,12 @@ The final planning summary must show Goal, In Scope, Out of Scope, Acceptance Cr
|
|
|
157
184
|
- confirmed facts
|
|
158
185
|
- requirements
|
|
159
186
|
- acceptance criteria
|
|
187
|
+
- not yet specified
|
|
160
188
|
- out of scope
|
|
161
189
|
- open questions that still block planning
|
|
162
190
|
|
|
191
|
+
**Not yet specified** and **out of scope** are different rejections and must not be merged. Not-yet-specified is inside this task's boundary but not sharp enough to state as a question yet; it graduates into a real question once an earlier decision clears the way. Out-of-scope is ruled outside the boundary and never graduates. The test is sharpness, not answerability: if you can phrase the question precisely right now, it belongs on the frontier or in a later round even when nothing can answer it yet. Collapsing the two loses work in both directions — a vague item gets treated as decided against, or a decided-against item gets treated as pending.
|
|
192
|
+
|
|
163
193
|
`design.md` records technical design:
|
|
164
194
|
|
|
165
195
|
- architecture and boundaries
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
Comprehensive quality verification for recently written code. Combines spec compliance, cross-layer safety, and pre-commit checks.
|
|
4
4
|
|
|
5
|
+
**Authorization**: Step 6 sets the fix boundary — mechanical and local you fix, judgment calls you record. Committing and pushing sit outside that boundary in both directions: a check request never carries them, so ask for them separately. Running as a dispatched `trellis-check` sub-agent there is no user turn to ask in, so send the recommendation up to the main session instead of stopping and instead of widening the change on your own.
|
|
6
|
+
|
|
7
|
+
**Done when**: every changed file has been read against the task's acceptance criteria, the project's checks have run in this session with their output shown, and each finding is either fixed or recorded with a recommendation.
|
|
8
|
+
|
|
5
9
|
---
|
|
6
10
|
|
|
7
11
|
## Step 1: Identify What Changed
|
|
@@ -33,7 +37,14 @@ Read the specific guideline files referenced — the index is a pointer, not the
|
|
|
33
37
|
|
|
34
38
|
## Step 3: Run Project Checks
|
|
35
39
|
|
|
36
|
-
Run the project's lint, type-check, and test commands.
|
|
40
|
+
Run the project's lint, type-check, and test commands. A failure that is mechanical and local — the kinds Step 6 lists — gets fixed here and the checks re-run. Anything needing a judgment call, a public interface change, or an edit outside this task's scope stops here and goes to Step 6 as a finding; being mid-check is not authorization to make that change.
|
|
41
|
+
|
|
42
|
+
Red evidence gates the code that gets written; these three rules gate the green you report afterwards.
|
|
43
|
+
|
|
44
|
+
- **No unverified claims.** Do not write "tests pass", "I verified X", or "this fixes Y" unless that command's output is in this session's transcript. Where you reasoned from reading the code instead of running it, say so in those words.
|
|
45
|
+
- **A green that never ran the path is not a pass.** A pass counts only when at least one non-skipped, non-empty case exercised the code under review, and the assertion would fail if the output were empty. Three shapes report green without testing anything: a job skipped for a missing optional dependency that still prints OK; an early return leaving output empty so a true-on-empty assertion passes; a rendered surface declared fixed but never opened. A negative assertion ("output must not contain X") needs a paired positive case proving it can fail at all.
|
|
46
|
+
- **Classify the failure layer before calling the repo broken.** A verifier that dies before its assertions run — missing optional dependency, bootstrap noise, tool setup, a crashed build service — is a setup failure, not a product failure. Name which one it is; retry only with new evidence or a narrower environment.
|
|
47
|
+
- **When the environment cannot run a check at all, record that instead of claiming or skipping it.** Name the check, why this environment cannot run it (no browser, no display, no device, no credentials), and what remains unverified. An unrunnable check is a stated gap; it is never a box to tick.
|
|
37
48
|
|
|
38
49
|
## Step 4: Review Against Checklist
|
|
39
50
|
|
|
@@ -65,6 +76,16 @@ Run the project's lint, type-check, and test commands. Fix any failures before p
|
|
|
65
76
|
- [ ] Any file changed that the acceptance criteria do not mention?
|
|
66
77
|
- [ ] Any workaround added at the caller instead of a fix where the behavior actually lives?
|
|
67
78
|
|
|
79
|
+
### Pattern-Fix Completeness
|
|
80
|
+
|
|
81
|
+
Required whenever this change fixed a defect. One fixed instance of a class-of-bug usually leaves siblings in the tree, and a local fix that ignores them leaves the rest of them shipped.
|
|
82
|
+
|
|
83
|
+
1. Name the **pattern signature** — the specific call, regex, selector, missing guard, lock acquisition, or input boundary that produced the defect.
|
|
84
|
+
2. Search that signature across the repo with `rg`, which respects `.gitignore` and so skips generated output, build artifacts, and vendored dependencies by default. (`grep -rn` excludes nothing and will walk `node_modules`.) For a class-of-bug ("every handler that skips the lock"), search the surrounding shape rather than the literal text.
|
|
85
|
+
3. Rule on **every** match in writing: same bug, or safe to leave with the reason, or unsure and put to the user. A match passed over silently is itself a finding.
|
|
86
|
+
|
|
87
|
+
Unrelated defects the sweep turns up get listed, not fixed here, unless the user agrees.
|
|
88
|
+
|
|
68
89
|
## Step 5: Cross-Layer Dimensions (if applicable)
|
|
69
90
|
|
|
70
91
|
Skip this step if your change is confined to a single layer.
|
|
@@ -6,6 +6,10 @@ Red evidence is one command you have **already executed** that goes red on the e
|
|
|
6
6
|
|
|
7
7
|
A lint pass, a successful build, or a green type-check is not red evidence. None of them can observe the behavior in question.
|
|
8
8
|
|
|
9
|
+
**Authorization**: building the loop, reproducing, minimising, and hypothesising are report-only. Writing production code needs the current turn to ask for a fix — a request to reproduce or diagnose is not one. The red evidence is required either way.
|
|
10
|
+
|
|
11
|
+
**Done when**: the red command has been run and its redacted output recorded in the artifact named under Recording the Evidence; and, for a fix, that same command has been re-run against the original scenario and observed green.
|
|
12
|
+
|
|
9
13
|
---
|
|
10
14
|
|
|
11
15
|
## Which Path Applies
|
|
@@ -275,6 +275,30 @@ good code example
|
|
|
275
275
|
> Details about when this happens and how to handle it.
|
|
276
276
|
```
|
|
277
277
|
|
|
278
|
+
### Adding a Failure-Derived Rule
|
|
279
|
+
|
|
280
|
+
For something that went wrong once and must not again, where one line states the rule. Append a row to the owning document's rule table, creating the table on first use:
|
|
281
|
+
|
|
282
|
+
```markdown
|
|
283
|
+
## Rules learned the hard way
|
|
284
|
+
|
|
285
|
+
| What happened | Rule |
|
|
286
|
+
|---|---|
|
|
287
|
+
| Changed a signature, missed three call sites the type checker could not see through dynamic dispatch | Grep the symbol name; a green type check does not prove the call sites were found |
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
`What happened` is the specific failure as it actually occurred, not an abstract symptom — the concrete case is what makes the rule stick, and an abstract one reads as generic advice. `Rule` is one imperative sentence.
|
|
291
|
+
|
|
292
|
+
Pick the coarsest form that still carries the lesson:
|
|
293
|
+
|
|
294
|
+
| Form | Use when |
|
|
295
|
+
|---|---|
|
|
296
|
+
| A row in the table above | One line states the rule. The default. |
|
|
297
|
+
| `Common Mistake` block | The causal chain needs Symptom / Cause / Fix / Prevention spelled out separately |
|
|
298
|
+
| Inline `> **Gotcha**` | The warning only makes sense beside one specific passage |
|
|
299
|
+
|
|
300
|
+
A `trellis-break-loop` retrospective lands here: every prevention mechanism it named becomes a row in the spec document that owns that area. An analysis left in the chat prevents nothing.
|
|
301
|
+
|
|
278
302
|
---
|
|
279
303
|
|
|
280
304
|
## Interactive Mode
|
|
@@ -21,6 +21,7 @@ export declare const frontendHookGuidelinesContent: string;
|
|
|
21
21
|
export declare const frontendComponentGuidelinesContent: string;
|
|
22
22
|
export declare const frontendQualityGuidelinesContent: string;
|
|
23
23
|
export declare const frontendStateManagementContent: string;
|
|
24
|
+
export declare const frontendVisualDesignContent: string;
|
|
24
25
|
export declare const guidesIndexContent: string;
|
|
25
26
|
export declare const guidesCrossLayerThinkingGuideContent: string;
|
|
26
27
|
export declare const guidesCodeReuseThinkingGuideContent: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/markdown/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAqBH,eAAO,MAAM,eAAe,EAAE,MAAuC,CAAC;AAGtE,eAAO,MAAM,qBAAqB,EAAE,MACK,CAAC;AAG1C,eAAO,MAAM,yBAAyB,QAAwB,CAAC;AAG/D,eAAO,MAAM,wBAAwB,EAAE,MACH,CAAC;AAQrC,eAAO,MAAM,mBAAmB,EAAE,MAEjC,CAAC;AACF,eAAO,MAAM,gCAAgC,EAAE,MAE9C,CAAC;AACF,eAAO,MAAM,gCAAgC,EAAE,MAE9C,CAAC;AACF,eAAO,MAAM,+BAA+B,EAAE,MAE7C,CAAC;AACF,eAAO,MAAM,+BAA+B,EAAE,MAE7C,CAAC;AACF,eAAO,MAAM,2BAA2B,EAAE,MAEzC,CAAC;AAGF,eAAO,MAAM,oBAAoB,EAAE,MAElC,CAAC;AACF,eAAO,MAAM,iCAAiC,EAAE,MAE/C,CAAC;AACF,eAAO,MAAM,yBAAyB,EAAE,MAEvC,CAAC;AACF,eAAO,MAAM,6BAA6B,EAAE,MAE3C,CAAC;AACF,eAAO,MAAM,kCAAkC,EAAE,MAEhD,CAAC;AACF,eAAO,MAAM,gCAAgC,EAAE,MAE9C,CAAC;AACF,eAAO,MAAM,8BAA8B,EAAE,MAE5C,CAAC;AAGF,eAAO,MAAM,kBAAkB,EAAE,MAEhC,CAAC;AACF,eAAO,MAAM,oCAAoC,EAAE,MAElD,CAAC;AACF,eAAO,MAAM,mCAAmC,EAAE,MAEjD,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/markdown/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAqBH,eAAO,MAAM,eAAe,EAAE,MAAuC,CAAC;AAGtE,eAAO,MAAM,qBAAqB,EAAE,MACK,CAAC;AAG1C,eAAO,MAAM,yBAAyB,QAAwB,CAAC;AAG/D,eAAO,MAAM,wBAAwB,EAAE,MACH,CAAC;AAQrC,eAAO,MAAM,mBAAmB,EAAE,MAEjC,CAAC;AACF,eAAO,MAAM,gCAAgC,EAAE,MAE9C,CAAC;AACF,eAAO,MAAM,gCAAgC,EAAE,MAE9C,CAAC;AACF,eAAO,MAAM,+BAA+B,EAAE,MAE7C,CAAC;AACF,eAAO,MAAM,+BAA+B,EAAE,MAE7C,CAAC;AACF,eAAO,MAAM,2BAA2B,EAAE,MAEzC,CAAC;AAGF,eAAO,MAAM,oBAAoB,EAAE,MAElC,CAAC;AACF,eAAO,MAAM,iCAAiC,EAAE,MAE/C,CAAC;AACF,eAAO,MAAM,yBAAyB,EAAE,MAEvC,CAAC;AACF,eAAO,MAAM,6BAA6B,EAAE,MAE3C,CAAC;AACF,eAAO,MAAM,kCAAkC,EAAE,MAEhD,CAAC;AACF,eAAO,MAAM,gCAAgC,EAAE,MAE9C,CAAC;AACF,eAAO,MAAM,8BAA8B,EAAE,MAE5C,CAAC;AAEF,eAAO,MAAM,2BAA2B,EAAE,MAEzC,CAAC;AAGF,eAAO,MAAM,kBAAkB,EAAE,MAEhC,CAAC;AACF,eAAO,MAAM,oCAAoC,EAAE,MAElD,CAAC;AACF,eAAO,MAAM,mCAAmC,EAAE,MAEjD,CAAC"}
|
|
@@ -45,6 +45,8 @@ export const frontendHookGuidelinesContent = readLocalTemplate("spec/frontend/ho
|
|
|
45
45
|
export const frontendComponentGuidelinesContent = readLocalTemplate("spec/frontend/component-guidelines.md.txt");
|
|
46
46
|
export const frontendQualityGuidelinesContent = readLocalTemplate("spec/frontend/quality-guidelines.md.txt");
|
|
47
47
|
export const frontendStateManagementContent = readLocalTemplate("spec/frontend/state-management.md.txt");
|
|
48
|
+
// Ships filled in, unlike its siblings: visual craft rules a codebase cannot state.
|
|
49
|
+
export const frontendVisualDesignContent = readLocalTemplate("spec/frontend/visual-design.md.txt");
|
|
48
50
|
// Guides structure
|
|
49
51
|
export const guidesIndexContent = readLocalTemplate("spec/guides/index.md.txt");
|
|
50
52
|
export const guidesCrossLayerThinkingGuideContent = readLocalTemplate("spec/guides/cross-layer-thinking-guide.md.txt");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/markdown/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC;;GAEG;AACH,SAAS,iBAAiB,CAAC,QAAgB;IACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAC3C,OAAO,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AACzC,CAAC;AAED,gFAAgF;AAChF,8BAA8B;AAC9B,gFAAgF;AAEhF,MAAM,CAAC,MAAM,eAAe,GAAW,iBAAiB,CAAC,WAAW,CAAC,CAAC;AAEtE,oDAAoD;AACpD,MAAM,CAAC,MAAM,qBAAqB,GAChC,iBAAiB,CAAC,oBAAoB,CAAC,CAAC;AAE1C,gCAAgC;AAChC,MAAM,CAAC,MAAM,yBAAyB,GAAG,qBAAqB,CAAC;AAE/D,2DAA2D;AAC3D,MAAM,CAAC,MAAM,wBAAwB,GACnC,iBAAiB,CAAC,eAAe,CAAC,CAAC;AAErC,gFAAgF;AAChF,0DAA0D;AAC1D,wEAAwE;AACxE,gFAAgF;AAEhF,uCAAuC;AACvC,MAAM,CAAC,MAAM,mBAAmB,GAAW,iBAAiB,CAC1D,2BAA2B,CAC5B,CAAC;AACF,MAAM,CAAC,MAAM,gCAAgC,GAAW,iBAAiB,CACvE,yCAAyC,CAC1C,CAAC;AACF,MAAM,CAAC,MAAM,gCAAgC,GAAW,iBAAiB,CACvE,yCAAyC,CAC1C,CAAC;AACF,MAAM,CAAC,MAAM,+BAA+B,GAAW,iBAAiB,CACtE,wCAAwC,CACzC,CAAC;AACF,MAAM,CAAC,MAAM,+BAA+B,GAAW,iBAAiB,CACtE,wCAAwC,CACzC,CAAC;AACF,MAAM,CAAC,MAAM,2BAA2B,GAAW,iBAAiB,CAClE,oCAAoC,CACrC,CAAC;AAEF,wCAAwC;AACxC,MAAM,CAAC,MAAM,oBAAoB,GAAW,iBAAiB,CAC3D,4BAA4B,CAC7B,CAAC;AACF,MAAM,CAAC,MAAM,iCAAiC,GAAW,iBAAiB,CACxE,0CAA0C,CAC3C,CAAC;AACF,MAAM,CAAC,MAAM,yBAAyB,GAAW,iBAAiB,CAChE,kCAAkC,CACnC,CAAC;AACF,MAAM,CAAC,MAAM,6BAA6B,GAAW,iBAAiB,CACpE,sCAAsC,CACvC,CAAC;AACF,MAAM,CAAC,MAAM,kCAAkC,GAAW,iBAAiB,CACzE,2CAA2C,CAC5C,CAAC;AACF,MAAM,CAAC,MAAM,gCAAgC,GAAW,iBAAiB,CACvE,yCAAyC,CAC1C,CAAC;AACF,MAAM,CAAC,MAAM,8BAA8B,GAAW,iBAAiB,CACrE,uCAAuC,CACxC,CAAC;AAEF,mBAAmB;AACnB,MAAM,CAAC,MAAM,kBAAkB,GAAW,iBAAiB,CACzD,0BAA0B,CAC3B,CAAC;AACF,MAAM,CAAC,MAAM,oCAAoC,GAAW,iBAAiB,CAC3E,+CAA+C,CAChD,CAAC;AACF,MAAM,CAAC,MAAM,mCAAmC,GAAW,iBAAiB,CAC1E,8CAA8C,CAC/C,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/markdown/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC;;GAEG;AACH,SAAS,iBAAiB,CAAC,QAAgB;IACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAC3C,OAAO,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AACzC,CAAC;AAED,gFAAgF;AAChF,8BAA8B;AAC9B,gFAAgF;AAEhF,MAAM,CAAC,MAAM,eAAe,GAAW,iBAAiB,CAAC,WAAW,CAAC,CAAC;AAEtE,oDAAoD;AACpD,MAAM,CAAC,MAAM,qBAAqB,GAChC,iBAAiB,CAAC,oBAAoB,CAAC,CAAC;AAE1C,gCAAgC;AAChC,MAAM,CAAC,MAAM,yBAAyB,GAAG,qBAAqB,CAAC;AAE/D,2DAA2D;AAC3D,MAAM,CAAC,MAAM,wBAAwB,GACnC,iBAAiB,CAAC,eAAe,CAAC,CAAC;AAErC,gFAAgF;AAChF,0DAA0D;AAC1D,wEAAwE;AACxE,gFAAgF;AAEhF,uCAAuC;AACvC,MAAM,CAAC,MAAM,mBAAmB,GAAW,iBAAiB,CAC1D,2BAA2B,CAC5B,CAAC;AACF,MAAM,CAAC,MAAM,gCAAgC,GAAW,iBAAiB,CACvE,yCAAyC,CAC1C,CAAC;AACF,MAAM,CAAC,MAAM,gCAAgC,GAAW,iBAAiB,CACvE,yCAAyC,CAC1C,CAAC;AACF,MAAM,CAAC,MAAM,+BAA+B,GAAW,iBAAiB,CACtE,wCAAwC,CACzC,CAAC;AACF,MAAM,CAAC,MAAM,+BAA+B,GAAW,iBAAiB,CACtE,wCAAwC,CACzC,CAAC;AACF,MAAM,CAAC,MAAM,2BAA2B,GAAW,iBAAiB,CAClE,oCAAoC,CACrC,CAAC;AAEF,wCAAwC;AACxC,MAAM,CAAC,MAAM,oBAAoB,GAAW,iBAAiB,CAC3D,4BAA4B,CAC7B,CAAC;AACF,MAAM,CAAC,MAAM,iCAAiC,GAAW,iBAAiB,CACxE,0CAA0C,CAC3C,CAAC;AACF,MAAM,CAAC,MAAM,yBAAyB,GAAW,iBAAiB,CAChE,kCAAkC,CACnC,CAAC;AACF,MAAM,CAAC,MAAM,6BAA6B,GAAW,iBAAiB,CACpE,sCAAsC,CACvC,CAAC;AACF,MAAM,CAAC,MAAM,kCAAkC,GAAW,iBAAiB,CACzE,2CAA2C,CAC5C,CAAC;AACF,MAAM,CAAC,MAAM,gCAAgC,GAAW,iBAAiB,CACvE,yCAAyC,CAC1C,CAAC;AACF,MAAM,CAAC,MAAM,8BAA8B,GAAW,iBAAiB,CACrE,uCAAuC,CACxC,CAAC;AACF,oFAAoF;AACpF,MAAM,CAAC,MAAM,2BAA2B,GAAW,iBAAiB,CAClE,oCAAoC,CACrC,CAAC;AAEF,mBAAmB;AACnB,MAAM,CAAC,MAAM,kBAAkB,GAAW,iBAAiB,CACzD,0BAA0B,CAC3B,CAAC;AACF,MAAM,CAAC,MAAM,oCAAoC,GAAW,iBAAiB,CAC3E,+CAA+C,CAChD,CAAC;AACF,MAAM,CAAC,MAAM,mCAAmC,GAAW,iBAAiB,CAC1E,8CAA8C,CAC/C,CAAC"}
|
|
@@ -22,6 +22,35 @@ This directory contains guidelines for backend development. Fill in each file wi
|
|
|
22
22
|
|
|
23
23
|
---
|
|
24
24
|
|
|
25
|
+
## Pre-Development Checklist
|
|
26
|
+
|
|
27
|
+
Read before writing backend code. `trellis-before-dev` follows this section.
|
|
28
|
+
|
|
29
|
+
1. **Read the conventions that apply** — the files above covering the layers this change touches, plus `.trellis/spec/guides/` for the cross-cutting thinking guides. When the change reaches a rendered surface and `../frontend/visual-design.md` exists, read that too.
|
|
30
|
+
2. **State the change boundary.** The smallest behavior gap between what happens now and what should happen; where that behavior actually lives (not where it is easiest to intercept); which files you expect to change and why each is necessary; what you are explicitly not doing.
|
|
31
|
+
3. **Name the contract you are about to touch.** Any change to a public function signature, HTTP route, event payload, database schema, or config key has callers. Find them before editing, not after.
|
|
32
|
+
4. **Decide where the test will sit** before writing code, on a boundary that survives a refactor of the implementation behind it.
|
|
33
|
+
|
|
34
|
+
Fill this section in with your project's own specifics — the commands to run, the layers that need extra care, the areas where mistakes have been costly. The four items above are the platform-neutral floor.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Quality Check
|
|
39
|
+
|
|
40
|
+
Run before reporting a backend change complete. `trellis-check` follows this section.
|
|
41
|
+
|
|
42
|
+
- [ ] Project lint, type-check, and tests pass, with the output shown in this session.
|
|
43
|
+
- [ ] New behavior has a test on the boundary chosen above; a bug fix has a regression test that was observed failing before the fix.
|
|
44
|
+
- [ ] Every caller of a changed contract was found and updated. A green type check does not prove this where dispatch is dynamic — search for the symbol.
|
|
45
|
+
- [ ] Errors are propagated or handled deliberately, never swallowed. No debug logging left behind.
|
|
46
|
+
- [ ] No credential, token, or personal data in logs, error messages, or committed fixtures.
|
|
47
|
+
- [ ] Migrations run forward on a copy of real-shaped data, and the rollback path is known.
|
|
48
|
+
- [ ] A change that reached a rendered surface was verified against `../frontend/visual-design.md` → **Verification**, which owns the render rules and the no-renderer fallback. Skip this line where that file does not exist in this project.
|
|
49
|
+
|
|
50
|
+
Replace and extend these with your project's actual gates — the real verification commands, the real risky areas.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
25
54
|
## How to Fill These Guidelines
|
|
26
55
|
|
|
27
56
|
For each guideline file:
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
This directory contains guidelines for frontend development. Fill in each file with your project's specific conventions.
|
|
10
10
|
|
|
11
|
+
One file is the exception: `visual-design.md` ships filled in, because visual craft rules are general knowledge no codebase can state. Read it as-is; override a rule where your project has decided against it.
|
|
12
|
+
|
|
11
13
|
---
|
|
12
14
|
|
|
13
15
|
## Guidelines Index
|
|
@@ -20,6 +22,37 @@ This directory contains guidelines for frontend development. Fill in each file w
|
|
|
20
22
|
| [State Management](./state-management.md) | Local state, global state, server state | To fill |
|
|
21
23
|
| [Quality Guidelines](./quality-guidelines.md) | Code standards, forbidden patterns | To fill |
|
|
22
24
|
| [Type Safety](./type-safety.md) | Type patterns, validation | To fill |
|
|
25
|
+
| [Visual Design](./visual-design.md) | Typography, color, motion, surfaces, banned patterns, render verification | Ready to use |
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Pre-Development Checklist
|
|
30
|
+
|
|
31
|
+
Read before writing frontend code. `trellis-before-dev` follows this section.
|
|
32
|
+
|
|
33
|
+
1. **Read the conventions that apply.** The files above covering the layers you are about to touch — component patterns, state, types — plus `visual-design.md` whenever the change is visible on screen.
|
|
34
|
+
2. **Lock the visual direction before the first component.** Infer each of these from the existing product, its tokens, and its sibling components first; ask only where a missing answer would change what you build, and state your inferred answer for the rest so it can be corrected.
|
|
35
|
+
- Who uses this surface, and in what context? A dense analyst view is not a landing page.
|
|
36
|
+
- What is the aesthetic direction, named precisely? "Clean and modern" is not a direction. If the user names a reference product, do not accept the name — extract three concrete properties from it (radius philosophy, how depth is expressed, accent family) and name those.
|
|
37
|
+
- What are the hard constraints? Framework, bundle size, contrast minimums, keyboard access.
|
|
38
|
+
- Which single CSS strategy applies? Name it once, then do not drift. See the stack-conflict table in `visual-design.md`.
|
|
39
|
+
- Does anything move, and if so what? `none` with a reason is a valid answer for a quiet utility surface.
|
|
40
|
+
3. **Adding to a mature product skips the direction question — the direction is the product.** Grep for the nearest existing sibling component and reuse its container, motion, and type tokens. Inventing a new style needs a stated reason why no existing component fits.
|
|
41
|
+
4. **State the change boundary.** The smallest behavior gap, where that behavior actually lives, which files you expect to touch, and what you are explicitly not doing.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Quality Check
|
|
46
|
+
|
|
47
|
+
Run before reporting a frontend change complete. `trellis-check` follows this section.
|
|
48
|
+
|
|
49
|
+
- [ ] Project lint, type-check, and tests pass, with the output shown in this session.
|
|
50
|
+
- [ ] `visual-design.md` → **Verification** worked through end to end, including its no-renderer clause for an environment that cannot open the screen. That section owns the render rules — restating them here would just leave two copies to drift.
|
|
51
|
+
- [ ] `visual-design.md` → **Absolute Bans**: nothing slipped in unintentionally, and where the committed direction genuinely required breaking one, the tradeoff is named.
|
|
52
|
+
- [ ] `visual-design.md` → **Surface Hierarchy** and **Accessibility Baseline** both hold.
|
|
53
|
+
- [ ] `visual-design.md` → **AI Slop Test** passes.
|
|
54
|
+
|
|
55
|
+
Replace and extend these with your project's actual gates — the real dev-server command, the real screens to open, the surfaces that have broken before.
|
|
23
56
|
|
|
24
57
|
---
|
|
25
58
|
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# Visual Design Rules
|
|
2
|
+
|
|
3
|
+
> **This file ships filled in.** Unlike its siblings in this directory, it is not a "document your project's conventions" stub. These rules are general craft knowledge that a codebase cannot tell you — no config file states which typefaces read as unconsidered, and no linter catches a purple-to-blue gradient. Delete or override any rule your project has deliberately decided against, and record the reason where you override it.
|
|
4
|
+
>
|
|
5
|
+
> Project-specific token values (your palette, your type scale, your radius scale) belong in a `DESIGN.md`-style section you add at the bottom, or in `component-guidelines.md`. This file holds the rules that hold regardless of project.
|
|
6
|
+
>
|
|
7
|
+
> **Scope and shelf life.** Written for web UI: the mechanisms named are CSS, and a React Native / Flutter / desktop-toolkit surface should read the intent and ignore the syntax. Two kinds of content here decay — the browser baselines under Motion, and the typeface list under Typography — so treat both as "true when written" and re-check before leaning on them. Rules as of Trellis 0.7.3 (2026-08).
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Absolute Bans
|
|
12
|
+
|
|
13
|
+
Each of these appears in the majority of AI-generated interfaces. Each has a specific rewrite. Any of them may appear when the committed direction genuinely calls for it — never by default, and the tradeoff gets named.
|
|
14
|
+
|
|
15
|
+
| Pattern | Why | Rewrite |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| `border-left` / `border-right` wider than 1px as a section accent | The most overused "design touch" in dashboard UIs; beyond a hairline it reads as a mistake | Change the structure: a colored dot, a short horizontal rule, a background swatch, or a weight shift |
|
|
18
|
+
| `background-clip: text` gradient text | Decorative, not meaningful; illegible in print and high-contrast mode | Solid brand color, tinted neutral, or typographic weight |
|
|
19
|
+
| `backdrop-filter: blur` glass as the default card surface | Expensive on low-power devices, and the layered-depth illusion breaks against a solid border | Background-color steps plus `box-shadow` |
|
|
20
|
+
| Purple-to-blue gradients, cyan-on-dark accents | The canonical "AI palette"; communicates nothing about the product | Derive the palette from the brand words via the color rules below |
|
|
21
|
+
| Rounded-rect card with `box-shadow` as the default container | Applies one container to every content type regardless of hierarchy | Default to cardless sections; add card treatment only when the content type needs it |
|
|
22
|
+
| Modal as the escape hatch for overflow | Interrupts flow, breaks back navigation | Inline expansion, detail panel, or a route; modal only when the action truly needs focus-lock |
|
|
23
|
+
| `transition: all` | Transitions every animatable property, including ones you never meant to touch, and re-runs on unrelated changes | Name exact properties: `transition-property: transform, opacity` |
|
|
24
|
+
| Animating `width` / `height` / `padding` / `margin` | Forces layout recalculation every frame | Animate `transform` instead. Height reveal is the one case with no transform equivalent — see the exception under Motion |
|
|
25
|
+
|
|
26
|
+
**Template test**: swap in completely different content. If the layout still works with no changes, that is a template, not a design.
|
|
27
|
+
|
|
28
|
+
## Typography
|
|
29
|
+
|
|
30
|
+
Reject as a *display* face: Inter, DM Sans, DM Serif, Outfit, Plus Jakarta Sans, Instrument Sans/Serif, Space Grotesk, Space Mono, IBM Plex, Syne, Fraunces, Newsreader, Lora, Crimson, Playfair Display, Cormorant. These dominate training data, so reaching for one signals that no decision was made. Informed product-UI use is fine when justified — Inter in a dense data table is a decision; Inter as a landing-page display face is a reflex. The list is not exhaustive: any face chosen without a stated reason belongs on it.
|
|
31
|
+
|
|
32
|
+
Selection: write three words for the brand, name the three faces you would reach for reflexively, reject all three, then pick one you can justify in a sentence.
|
|
33
|
+
|
|
34
|
+
Details that separate typeset from typed:
|
|
35
|
+
|
|
36
|
+
- Letter-spacing scales with size. Display type needs negative tracking: about `-0.022em` at 32px and above, `-0.012em` at 20–28px, normal at 16px and below. Positive tracking on a large headline is always wrong.
|
|
37
|
+
- `text-wrap: balance` on headings and short blocks; `text-wrap: pretty` on body copy; leave code blocks alone.
|
|
38
|
+
- `font-variant-numeric: tabular-nums` for counters, timers, prices, and any number that updates in place.
|
|
39
|
+
- Constrain body paragraphs to roughly 65 characters.
|
|
40
|
+
|
|
41
|
+
### CJK and mixed script
|
|
42
|
+
|
|
43
|
+
Latin-only rules silently break CJK text.
|
|
44
|
+
|
|
45
|
+
- Latin face first, CJK face after, so each script gets correct glyphs: `-apple-system, "SF Pro Text", "PingFang SC", "Noto Sans SC", sans-serif`.
|
|
46
|
+
- CJK body copy needs more line-height than Latin: roughly 1.7–1.8 against Latin's 1.4–1.5.
|
|
47
|
+
- Tag runs with `lang="zh"` / `lang="ja"` / `lang="en"` so the browser picks the right face and line-breaking.
|
|
48
|
+
- A serif reading mode needs an explicit CJK serif fallback, or the toggle silently drops Chinese back to sans: `"Newsreader", "Songti SC", "Noto Serif SC", serif`.
|
|
49
|
+
- Never apply negative letter-spacing to CJK runs. Scope the tracking rule above to `lang="en"`.
|
|
50
|
+
|
|
51
|
+
## Color
|
|
52
|
+
|
|
53
|
+
- Use OKLCH over HSL: it is perceptually uniform, so equal numeric steps read as equal perceived steps.
|
|
54
|
+
- Reduce chroma toward the lightness extremes. At 85% lightness, chroma around 0.08 is plenty; 0.15 looks garish.
|
|
55
|
+
- Tint neutrals toward the brand hue at chroma 0.005–0.01. Even that faint amount reads as cohesion.
|
|
56
|
+
- 60-30-10 is about visual weight, not pixel count: 60% surface, 30% secondary text and borders, 10% accent.
|
|
57
|
+
- Never gray text on a colored background. Use the background hue at reduced lightness.
|
|
58
|
+
- Light and dark are both deliberate choices, neither is the default. Dark suits data density and long low-light sessions; light suits trust, legibility, and ambient daytime use. If the context does not decide it, ship light first.
|
|
59
|
+
|
|
60
|
+
## Surface Hierarchy
|
|
61
|
+
|
|
62
|
+
Adjacent nested surfaces must be visually distinguishable, and the mechanism differs by mode.
|
|
63
|
+
|
|
64
|
+
- **Light**: at least a 4% lightness step between sidebar and main, and between main and cards; or a shadow of at least `0 1px 3px rgba(0,0,0,0.10)` on elevated cards. A white card on near-white with `0 1px 2px rgba(0,0,0,0.05)` is not depth, it is noise.
|
|
65
|
+
- **Dark**: the canvas is near-black solid; elevation comes from semi-transparent white on top of it — cards `rgba(255,255,255,0.02)`, elevated `0.04`, prominent `0.05`. Dark-on-dark drop shadows are nearly invisible, so luminance stepping is the depth cue.
|
|
66
|
+
- Prefer layered `box-shadow` over borders for elevation; reserve `border` for dividers and table cells.
|
|
67
|
+
- Concentric radius: `outerRadius = innerRadius + padding`. Past 24px padding, treat the layers as separate surfaces and choose independently.
|
|
68
|
+
- Commit to a named radius scale before the first component. Three or four tiers is enough.
|
|
69
|
+
|
|
70
|
+
## Motion
|
|
71
|
+
|
|
72
|
+
**Frequency decides whether a thing animates at all** — settle that before duration or curve. Nothing keyboard-initiated animates. Something triggered hundreds of times a day reads motion as lag, so it gets none. Occasional surfaces (modal, drawer, toast) get the standard treatment. Rare or once-only moments can carry delight. If the only answer to "why does this move" is that it looks nice, and the user sees it daily, delete it.
|
|
73
|
+
|
|
74
|
+
Once motion is earned:
|
|
75
|
+
|
|
76
|
+
- Duration follows the element: press feedback 100–160ms, tooltip 125–200ms, dropdown 150–250ms, modal or drawer 200–500ms. An interactive element over 300ms needs a stated reason.
|
|
77
|
+
- Perceived speed comes from the first frame, not the total. When something feels slow, fix the curve before the number.
|
|
78
|
+
- Default to exponential ease-out (`cubic-bezier(0.16,1,0.3,1)`), not bounce or elastic — real objects decelerate smoothly. A small bounce is right only where a finger is still driving the motion (drag-to-dismiss, press-and-hold).
|
|
79
|
+
- `ease-in` belongs on one thing only: a short exit. On an enter, hover, or press it delays the first frame and reads as lag.
|
|
80
|
+
- Never enter from `scale(0)`. Nothing physical appears out of nothing — enter from `scale(0.95)` with `opacity: 0`.
|
|
81
|
+
- Anchor the origin to the trigger: popovers, dropdowns, and tooltips scale from the control that opened them. Modals are the exception and stay centered.
|
|
82
|
+
- Animate `transform` and `opacity` only. These two composite without touching layout, so they are the only properties that stay cheap at 60fps.
|
|
83
|
+
- **The one exception: revealing height.** No transform expresses "grow to fit content", so a disclosure animation has to animate a layout property. Prefer `grid-template-rows: 0fr → 1fr` on a single-row grid — it is still layout work each frame, so it is not free, but it is confined to one subtree and needs no measured pixel height. Baseline: animatable `fr` interpolation needs Chrome/Edge 107+, Safari 16+, Firefox 127+ (checked 2026-08; re-verify before relying on it). Below that it snaps instead of animating, which is an acceptable degradation. Where the baseline is too new, animate `max-height` to a measured value, or cross-fade a pre-sized container. Do not extend this exception to width, padding, or margin — restructure instead so a `transform` on a child does the work.
|
|
84
|
+
- Never `transition: all`; name exact properties.
|
|
85
|
+
- Every pressable thing moves on press, not only on hover. Hover is pointer-only and does not exist on touch, so an unmoved control leaves the click unacknowledged. `scale(0.96)` on active, via a transition so the press can be interrupted.
|
|
86
|
+
- Wrap hover states in `@media (hover: hover)`. Without it, a tapped element on a touch screen keeps a stuck hover state until the next tap elsewhere.
|
|
87
|
+
- Honor `prefers-reduced-motion` (also listed under the accessibility baseline — that is where it is binding).
|
|
88
|
+
|
|
89
|
+
## Content Authenticity
|
|
90
|
+
|
|
91
|
+
Placeholder content that looks real but is not breaks the illusion the moment someone reads it.
|
|
92
|
+
|
|
93
|
+
- No filler names (John Doe, Jane Smith). Use culturally varied names with real specificity.
|
|
94
|
+
- No filler companies (Acme, Nexus, TechCorp). Give them a domain: Meridian Logistics, Hokkaido Ceramics.
|
|
95
|
+
- No Lorem Ipsum. Write short real copy at the layout's reading level.
|
|
96
|
+
- No round numbers in sample data. `99.94%` and `47.2%` read as measured; `99.99%` and `50%` read as invented.
|
|
97
|
+
- Repeated avatars must not share one image; repeated cards must not share one date.
|
|
98
|
+
- Sentence case on headings. Title Case On Every Heading is the loudest tell in body copy.
|
|
99
|
+
- Drop exclamation marks from success states ("Saved", not "Saved!"). Never open an error with "Oops!".
|
|
100
|
+
- No passive voice in errors: "We couldn't load your data. Try refreshing." beats "Something went wrong."
|
|
101
|
+
- Banned in hero copy and CTAs: Elevate, Seamless, Unleash, Delve, Tapestry, Game-changer, Next-Gen, "In the world of...". Name the specific value instead.
|
|
102
|
+
- When an asset is unavailable, use a labeled placeholder, not a low-quality imitation. Never draw illustrative imagery in inline SVG — SVG is for icons and geometric shapes.
|
|
103
|
+
|
|
104
|
+
## Stack Conflicts
|
|
105
|
+
|
|
106
|
+
These combinations produce silent failures. Name the single CSS strategy before the first component and do not drift from it.
|
|
107
|
+
|
|
108
|
+
| Never combine | Why |
|
|
109
|
+
|---|---|
|
|
110
|
+
| Tailwind + CSS Modules on one element | Specificity conflicts, unpredictable cascade |
|
|
111
|
+
| Framer Motion + CSS transitions on one property | Double-animating causes jank |
|
|
112
|
+
| styled-components / emotion + Tailwind | Two class systems fighting for the same node |
|
|
113
|
+
| Two or more icon sets | Size mismatches and visual inconsistency |
|
|
114
|
+
| Multiple display font families | Competing personalities cancel out |
|
|
115
|
+
| Glass `backdrop-filter` + solid 1px border | The solid edge shatters the layered illusion |
|
|
116
|
+
| Dark background + `#ffffff` text at full opacity | Too harsh; use `rgba(255,255,255,0.85)` |
|
|
117
|
+
| Tailwind v4 `@theme` + dynamically built class names | `@theme` generates utilities JIT; a name built from a variable is purged and the style silently vanishes. Use static class names, a safelist, or `:root` + `extend.colors` |
|
|
118
|
+
|
|
119
|
+
## Verification
|
|
120
|
+
|
|
121
|
+
A visual change is not verified by a type check, a passing build, or reading the CSS back. Editing the string is not seeing the screen.
|
|
122
|
+
|
|
123
|
+
- Open the rendered surface. Screenshot at 375px and 1280px, in every shipped locale.
|
|
124
|
+
- Several regression classes are invisible in source and only appear in the render: early wraps, orphaned separators, table overflow, localized text overflowing a fixed slot.
|
|
125
|
+
- **Line widows**: flag any text block whose last line is under roughly 13% of its widest line. Fix by trimming the copy so the block rebalances, not by adding a `max-width` cap — a cap narrower than its container wraps early and leaves a gap that reads as a premature break. Eyeballing misses these, and text nested in `<code>` hides them from grep.
|
|
126
|
+
- Never rely on `…` truncation to fit text in a fixed slot. Guarantee the fit: compact the format, cap to whole segments, or hard-trim. Metric and label footers must never tail-truncate.
|
|
127
|
+
- Test long words and localized strings inside buttons, tabs, nav, and compact cards before handoff.
|
|
128
|
+
|
|
129
|
+
**No renderer available.** Where the environment has no browser, display, device, or credentials for the running app, none of the above can be done — so state that rather than claiming or silently dropping it. Name which checks could not run, why, and what stays unverified, then hand off the exact URL or screen plus the pass/fail delta a human should look for. A recorded gap is a complete result; a claim of "looks right" from an unopened screen is not, and it is indistinguishable from real verification once it is written down.
|
|
130
|
+
|
|
131
|
+
## Accessibility Baseline
|
|
132
|
+
|
|
133
|
+
Non-negotiable regardless of direction.
|
|
134
|
+
|
|
135
|
+
- Icon-only buttons need `aria-label`.
|
|
136
|
+
- Actions are `<button>`, navigation is `<a>`. Never `<div onClick>`.
|
|
137
|
+
- Images need `alt`, or `alt=""` when decorative.
|
|
138
|
+
- Visible focus states. Never `outline: none` without a replacement.
|
|
139
|
+
- Honor `prefers-reduced-motion`.
|
|
140
|
+
- Never suppress pinch-zoom (`user-scalable=no`, `maximum-scale=1`). Low-vision users depend on it.
|
|
141
|
+
|
|
142
|
+
Two neighbouring rules that are **not** accessibility, listed here because they are often mistaken for it:
|
|
143
|
+
|
|
144
|
+
- `touch-action: manipulation` removes the ~300ms double-tap delay. It is a latency optimization, and it works by disabling double-tap zoom — a gesture some low-vision users rely on. Apply it to specific controls where the delay hurts, not globally, and never at the cost of pinch-zoom.
|
|
145
|
+
- Dropping white text to `rgba(255,255,255,0.85)` on a dark surface is a comfort choice, not a contrast rule, and it *lowers* the contrast ratio. Check the result against the contrast minimum you committed to in the direction; if the surface is near-black the ratio usually still passes, but verify rather than assume.
|
|
146
|
+
|
|
147
|
+
**Hit-target size** is a project decision, not one number. The published minimums disagree: WCAG 2.2 (2.5.8) sets 24×24 CSS px, Apple HIG says 44×44 pt, Material says 48×48 dp. Pick one for the project and record it in `component-guidelines.md`. Whatever you pick, extend the target with a centered pseudo-element when the visible control is smaller, and never let two targets overlap.
|
|
148
|
+
|
|
149
|
+
## AI Slop Test
|
|
150
|
+
|
|
151
|
+
Would a stranger glancing at the first viewport say "an AI made this"? If yes, the direction was not committed to. The usual causes: reflex font, default purple accent, centered hero with two side-by-side CTAs above three identical cards. Fix typography, color, or layout until the answer flips.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
*The rules in Absolute Bans, Typography, Color, Motion, and AI Slop Test are adapted from [tw93/Waza](https://github.com/tw93/Waza) (MIT), which in turn adapts material from [pbakaus/impeccable](https://github.com/pbakaus/impeccable) (Apache 2.0), [getdesign.md](https://getdesign.md) (MIT), and [Leonxlnx/taste-skill](https://github.com/Leonxlnx/taste-skill).*
|
|
@@ -76,6 +76,30 @@ session_auto_commit: false
|
|
|
76
76
|
# Default package used when --package is not specified.
|
|
77
77
|
# default_package: frontend
|
|
78
78
|
|
|
79
|
+
#-------------------------------------------------------------------------------
|
|
80
|
+
# Spec scaffolding
|
|
81
|
+
#-------------------------------------------------------------------------------
|
|
82
|
+
# `spec/frontend/visual-design.md` is the one spec file Trellis ships filled in
|
|
83
|
+
# rather than as a "document your conventions" stub, because visual craft rules
|
|
84
|
+
# are general knowledge no codebase can state. By default it lands only where a
|
|
85
|
+
# frontend layer was detected.
|
|
86
|
+
#
|
|
87
|
+
# - auto (default): written for a frontend or fullstack layer, skipped for a
|
|
88
|
+
# backend-only one.
|
|
89
|
+
# - always: also written into `spec/frontend/` for a backend-only layer, and
|
|
90
|
+
# nothing else from `spec/frontend/` is created. Choose this when backend work
|
|
91
|
+
# in this project regularly reaches a rendered surface.
|
|
92
|
+
#
|
|
93
|
+
# To turn it off, delete the file. `.trellis/spec/` is a protected path, so
|
|
94
|
+
# `trellis update` never writes it back.
|
|
95
|
+
#
|
|
96
|
+
# Read at `trellis init` time. A fresh project has no config.yaml yet, so
|
|
97
|
+
# `always` takes effect from the second `trellis init` onward — set it, then
|
|
98
|
+
# re-run `trellis init` to have the file appear.
|
|
99
|
+
#
|
|
100
|
+
# spec:
|
|
101
|
+
# visual_design: auto
|
|
102
|
+
|
|
79
103
|
#-------------------------------------------------------------------------------
|
|
80
104
|
# Default workflow
|
|
81
105
|
#-------------------------------------------------------------------------------
|
|
@@ -253,6 +253,7 @@ Tools: `trellis-implement` / `trellis-research` name sub-agent roles dispatched
|
|
|
253
253
|
Flow: `trellis-implement` -> `trellis-check` -> commit (Phase 3.4) -> `/trellis:finish-work`. Spec update (3.3) is on demand — run it when the user asks, not as part of the default flow.
|
|
254
254
|
Red before green: work the `implement.md` slice checklist one slice at a time — test at a seam confirmed in `design.md`, run it, paste the redacted red output into that slice entry, then write the minimum code to pass. No horizontal slicing, no tautological assertions, no refactoring inside a red-green cycle. `kind=chore` and repos with no runnable harness must state that in the slice entry instead of skipping silently. Load the `trellis-tdd` skill for the full contract.
|
|
255
255
|
Main-session default: dispatch implement/check sub-agents. Sub-agent self-exemption: if already running as `trellis-implement`, do NOT spawn another `trellis-implement` or `trellis-check`; if already running as `trellis-check`, do NOT spawn another `trellis-check` or `trellis-implement`. Dispatch is main session only.
|
|
256
|
+
Green is a claim to prove: never report "tests pass" without this session's command output; a run that skipped or never entered the path is not a pass even when it prints OK; a verifier dying before its assertions is a setup failure, not a product one.
|
|
256
257
|
Dispatch prompt starts with `Active task: <task path from task.py current>`. Read context: jsonl entries -> `prd.md` -> `design.md` -> `implement.md`.
|
|
257
258
|
[/workflow-state:in_progress]
|
|
258
259
|
|
|
@@ -265,6 +266,7 @@ Dispatch prompt starts with `Active task: <task path from task.py current>`. Rea
|
|
|
265
266
|
Flow: `trellis-before-dev` -> edit -> `trellis-check` -> validation -> commit (Phase 3.4) -> `/trellis:finish-work`. Spec update (3.3) is on demand — run it when the user asks, not as part of the default flow.
|
|
266
267
|
Red before green: work the `implement.md` slice checklist one slice at a time — test at a seam confirmed in `design.md`, run it, paste the redacted red output into that slice entry, then write the minimum code to pass. No horizontal slicing, no tautological assertions, no refactoring inside a red-green cycle. `kind=chore` and repos with no runnable harness must state that in the slice entry instead of skipping silently. Load the `trellis-tdd` skill for the full contract.
|
|
267
268
|
Do not dispatch implement/check sub-agents in inline mode.
|
|
269
|
+
Green is a claim to prove: never report "tests pass" without this session's command output; a run that skipped or never entered the path is not a pass even when it prints OK; a verifier dying before its assertions is a setup failure, not a product one.
|
|
268
270
|
Read context: `prd.md` -> `design.md` -> `implement.md`, plus relevant spec/research loaded by skills.
|
|
269
271
|
[/workflow-state:in_progress-inline]
|
|
270
272
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blulotus/trellis",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.3",
|
|
4
4
|
"description": "AI capabilities grow like ivy — Trellis provides the structure to guide them along a disciplined path",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"inquirer": "^9.3.7",
|
|
35
35
|
"undici": "^6.21.0",
|
|
36
36
|
"zod": "^4.4.2",
|
|
37
|
-
"@blulotus/trellis-core": "0.7.
|
|
37
|
+
"@blulotus/trellis-core": "0.7.3"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@eslint/js": "^9.18.0",
|