@zyaiting/keelson 0.4.0
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/LICENSE +21 -0
- package/README.md +101 -0
- package/README_CN.md +101 -0
- package/bin/keelson.js +15 -0
- package/hooks/codebuddy-session.mjs +67 -0
- package/hooks/opencode-session.mjs +65 -0
- package/hooks/prompt-state.mjs +66 -0
- package/hooks/session-start.mjs +94 -0
- package/package.json +64 -0
- package/registry/models.json +118 -0
- package/registry/platforms.json +92 -0
- package/skills/keelson/SKILL.md +44 -0
- package/skills/keelson/references/build.md +61 -0
- package/skills/keelson/references/context.md +34 -0
- package/skills/keelson/references/debug.md +46 -0
- package/skills/keelson/references/design-lenses.md +78 -0
- package/skills/keelson/references/discover.md +70 -0
- package/skills/keelson/references/engineer.md +110 -0
- package/skills/keelson/references/frontend-delivery.md +38 -0
- package/skills/keelson/references/frontend-interaction.md +31 -0
- package/skills/keelson/references/frontend-review.md +33 -0
- package/skills/keelson/references/frontend-visual.md +31 -0
- package/skills/keelson/references/frontend.md +33 -0
- package/skills/keelson/references/handoff.md +43 -0
- package/skills/keelson/references/harness.md +54 -0
- package/skills/keelson/references/interview.md +120 -0
- package/skills/keelson/references/land.md +47 -0
- package/skills/keelson/references/model.md +29 -0
- package/skills/keelson/references/plan.md +106 -0
- package/skills/keelson/references/reconcile.md +61 -0
- package/skills/keelson/references/shape.md +86 -0
- package/skills/keelson/references/verify.md +64 -0
- package/skills/keelson/templates/GLOSSARY.md +5 -0
- package/skills/keelson/templates/INTENT.md +22 -0
- package/skills/keelson/templates/NOW.md +9 -0
- package/skills/keelson/templates/README.md +60 -0
- package/skills/keelson/templates/ROADMAP.md +12 -0
- package/skills/keelson/templates/change-quick.md +16 -0
- package/skills/keelson/templates/change.md +32 -0
- package/skills/keelson/templates/delta-spec.md +12 -0
- package/skills/keelson/templates/handoff.md +27 -0
- package/skills/keelson/templates/ledger.md +3 -0
- package/skills/keelson/templates/resident-block.md +7 -0
- package/skills/keelson/templates/rules-general.md +10 -0
- package/skills/keelson/templates/rules-index.md +5 -0
- package/skills/keelson/templates/spec.md +14 -0
- package/skills/keelson/templates/tasks.md +9 -0
- package/skills/keelson/templates/workflow.md +18 -0
- package/skills/zh/keelson/SKILL.md +46 -0
- package/skills/zh/keelson/references/build.md +61 -0
- package/skills/zh/keelson/references/context.md +34 -0
- package/skills/zh/keelson/references/debug.md +46 -0
- package/skills/zh/keelson/references/design-lenses.md +78 -0
- package/skills/zh/keelson/references/discover.md +70 -0
- package/skills/zh/keelson/references/engineer.md +110 -0
- package/skills/zh/keelson/references/frontend-delivery.md +38 -0
- package/skills/zh/keelson/references/frontend-interaction.md +31 -0
- package/skills/zh/keelson/references/frontend-review.md +33 -0
- package/skills/zh/keelson/references/frontend-visual.md +31 -0
- package/skills/zh/keelson/references/frontend.md +33 -0
- package/skills/zh/keelson/references/handoff.md +43 -0
- package/skills/zh/keelson/references/harness.md +54 -0
- package/skills/zh/keelson/references/interview.md +120 -0
- package/skills/zh/keelson/references/land.md +47 -0
- package/skills/zh/keelson/references/model.md +29 -0
- package/skills/zh/keelson/references/plan.md +106 -0
- package/skills/zh/keelson/references/reconcile.md +61 -0
- package/skills/zh/keelson/references/shape.md +86 -0
- package/skills/zh/keelson/references/verify.md +64 -0
- package/skills/zh/keelson/templates/GLOSSARY.md +5 -0
- package/skills/zh/keelson/templates/INTENT.md +22 -0
- package/skills/zh/keelson/templates/NOW.md +9 -0
- package/skills/zh/keelson/templates/README.md +60 -0
- package/skills/zh/keelson/templates/ROADMAP.md +12 -0
- package/skills/zh/keelson/templates/change-quick.md +16 -0
- package/skills/zh/keelson/templates/change.md +32 -0
- package/skills/zh/keelson/templates/delta-spec.md +12 -0
- package/skills/zh/keelson/templates/handoff.md +27 -0
- package/skills/zh/keelson/templates/ledger.md +3 -0
- package/skills/zh/keelson/templates/resident-block.md +7 -0
- package/skills/zh/keelson/templates/rules-general.md +10 -0
- package/skills/zh/keelson/templates/rules-index.md +5 -0
- package/skills/zh/keelson/templates/spec.md +14 -0
- package/skills/zh/keelson/templates/tasks.md +9 -0
- package/skills/zh/keelson/templates/workflow.md +18 -0
- package/src/cli.js +87 -0
- package/src/commands/ablate.js +96 -0
- package/src/commands/ask.js +64 -0
- package/src/commands/attest.js +71 -0
- package/src/commands/check.js +127 -0
- package/src/commands/context.js +95 -0
- package/src/commands/design.js +63 -0
- package/src/commands/doctor.js +157 -0
- package/src/commands/focus.js +84 -0
- package/src/commands/guide.js +59 -0
- package/src/commands/handoff.js +41 -0
- package/src/commands/hook.js +23 -0
- package/src/commands/impact.js +58 -0
- package/src/commands/init.js +289 -0
- package/src/commands/land.js +258 -0
- package/src/commands/models.js +62 -0
- package/src/commands/new.js +70 -0
- package/src/commands/platforms.js +39 -0
- package/src/commands/retro.js +114 -0
- package/src/commands/status.js +115 -0
- package/src/commands/uninstall.js +30 -0
- package/src/commands/validate.js +117 -0
- package/src/lib/args.js +30 -0
- package/src/lib/changes.js +114 -0
- package/src/lib/check-activity.js +29 -0
- package/src/lib/config.js +102 -0
- package/src/lib/decisions.js +59 -0
- package/src/lib/evidence.js +127 -0
- package/src/lib/fs.js +126 -0
- package/src/lib/git.js +353 -0
- package/src/lib/glob.js +54 -0
- package/src/lib/health.js +113 -0
- package/src/lib/lifecycle.js +120 -0
- package/src/lib/maintenance.js +66 -0
- package/src/lib/markdown.js +438 -0
- package/src/lib/models.js +195 -0
- package/src/lib/out.js +13 -0
- package/src/lib/paths.js +82 -0
- package/src/lib/rules.js +27 -0
- package/src/lib/runtime-path.js +22 -0
- package/src/lib/session.js +100 -0
- package/src/lib/specs.js +345 -0
- package/src/lib/transaction.js +93 -0
- package/src/platforms/index.js +3 -0
- package/src/platforms/integration.js +384 -0
- package/src/platforms/registry.js +46 -0
- package/src/platforms/runtime.js +249 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Engineering method
|
|
2
|
+
|
|
3
|
+
Use this reference when a technical choice is non-obvious, expensive to reverse, or justified by a claim about performance, reliability, scalability, cost, or maintainability. This is a **method for choosing**, not another checklist. `model.md` owns domain language/boundaries; `design-lenses.md` tells you which risk dimension matters; this file tells you how to reason and gather evidence.
|
|
4
|
+
|
|
5
|
+
## Start from first principles, not inherited solutions
|
|
6
|
+
<!-- keelson: id=engineer.first-principles | without: a requested technology or existing convention is mistaken for the requirement itself, so the design optimizes a mechanism instead of the outcome | sunset: never -->
|
|
7
|
+
|
|
8
|
+
Before choosing a pattern or product, reduce the problem to six things:
|
|
9
|
+
|
|
10
|
+
1. **Observed facts** — what code, tests, telemetry, docs, or users actually establish.
|
|
11
|
+
2. **Outcome** — the observable result the change must create.
|
|
12
|
+
3. **Hard constraints** — compatibility, regulation, authorization, budget, platform, deadlines.
|
|
13
|
+
4. **Invariants** — what must remain true even if the implementation changes.
|
|
14
|
+
5. **Assumptions** — beliefs that are not yet evidence.
|
|
15
|
+
6. **Mechanisms** — cache, queue, service, database, framework, pattern, model stage, abstraction.
|
|
16
|
+
|
|
17
|
+
Mechanisms are hypotheses, not requirements. Strip the technology names out and ask: **if this mechanism did not exist, what property would fail?** Existing architecture is evidence and often a compatibility constraint, but “we already do it this way” is not by itself a reason to reproduce accidental complexity.
|
|
18
|
+
|
|
19
|
+
Prefer the smallest problem statement that preserves the outcome, constraints, and invariants. Do not solve a larger future problem unless the current contract or measured trend requires it.
|
|
20
|
+
|
|
21
|
+
## State a falsifiable claim before adding machinery
|
|
22
|
+
<!-- keelson: id=engineer.hypothesis | without: architecture is justified with adjectives such as "faster", "safer", or "more scalable", so success cannot be distinguished from coincidence | sunset: never -->
|
|
23
|
+
|
|
24
|
+
For a material uncertain choice, write the engineering claim in compact form before implementation:
|
|
25
|
+
|
|
26
|
+
```text
|
|
27
|
+
Hypothesis: mechanism X improves/protects response Y under condition Z.
|
|
28
|
+
Baseline: current or simpler design B.
|
|
29
|
+
Measure: M.
|
|
30
|
+
Decision threshold: T.
|
|
31
|
+
Budget: the smallest experiment that can discriminate.
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Examples: “A cache keeps list p95 below 200 ms at 500 rps”; “an idempotency key prevents duplicate charges under at-least-once retry”; “a second Agent review finds requirement gaps the implementer misses.”
|
|
35
|
+
|
|
36
|
+
If the claim cannot be measured directly, identify the strongest observable proxy or structural evidence. If neither exists, treat the choice as an owner trade-off or a reversible default, not as a proven engineering fact.
|
|
37
|
+
|
|
38
|
+
## Use the cheapest experiment that can change the decision
|
|
39
|
+
<!-- keelson: id=engineer.experiment | without: teams argue from intuition for hours when a thin end-to-end slice, spike, measurement, or failure injection could answer the question | sunset: never -->
|
|
40
|
+
|
|
41
|
+
Choose the least expensive probe that discriminates between designs:
|
|
42
|
+
|
|
43
|
+
- **Tracer bullet** — one real user action end to end through every necessary layer.
|
|
44
|
+
- **Spike / prototype** — throwaway code to learn an API, integration, UI interaction, or migration constraint.
|
|
45
|
+
- **measurement / load test** — performance or cost claim against a representative workload.
|
|
46
|
+
- **Failure injection** — timeout, retry, duplicate, crash, dependency loss, or partial failure.
|
|
47
|
+
- **Ablation / counterfactual** — remove or simplify the mechanism and see whether the claimed benefit disappears.
|
|
48
|
+
|
|
49
|
+
Record experimental facts in the ledger; promote only the resulting durable decision. Prototype code does not become production code merely because it worked once.
|
|
50
|
+
|
|
51
|
+
## Ablation is for attribution, not ceremony
|
|
52
|
+
<!-- keelson: id=engineer.ablation | without: every extra component survives because the full system passes, even when nobody has shown that the component contributes anything | sunset: never -->
|
|
53
|
+
|
|
54
|
+
When a mechanism claims to earn its complexity, compare it with a simpler baseline:
|
|
55
|
+
|
|
56
|
+
1. Keep workload, environment, configuration, dataset, and random seed as stable as practical.
|
|
57
|
+
2. Measure the baseline.
|
|
58
|
+
3. Disable, remove, or simplify the mechanism.
|
|
59
|
+
4. Measure the same response.
|
|
60
|
+
5. Compare the difference against the threshold chosen **before** looking at the result.
|
|
61
|
+
|
|
62
|
+
If the effect is negligible, the mechanism has not earned its complexity; remove it or mark the evidence inconclusive. If results are noisy, repeat rather than cherry-pick.
|
|
63
|
+
|
|
64
|
+
A one-factor-at-a-time ablation can miss interactions. If X may only help when Y is present, use the smallest useful combination matrix (often a 2×2) rather than concluding from isolated removals. The goal is causal information good enough for the engineering decision, not statistical theater.
|
|
65
|
+
|
|
66
|
+
## Escalate to architecture only when the cost of change says it matters
|
|
67
|
+
<!-- keelson: id=engineer.architecture | without: every code organization choice becomes "architecture", while genuinely hard-to-reverse boundaries are made without explicit trade-off analysis | sunset: never -->
|
|
68
|
+
|
|
69
|
+
Treat a decision as architecture when it is broad or expensive to reverse: data ownership/schema, public contracts, trust boundaries, deployment/service boundaries, concurrency model, durable storage, external platform dependency, or an operational topology that many changes will inherit.
|
|
70
|
+
|
|
71
|
+
For a material architecture fork:
|
|
72
|
+
|
|
73
|
+
- Write the relevant **quality-attribute scenario** as: stimulus → environment → expected response → measurable response.
|
|
74
|
+
- Sketch **two credible designs** before choosing. Do this only for a real fork, not to satisfy a template.
|
|
75
|
+
- Compare them against current needs: complexity, modifiability, reliability, security, performance/cost, testability, migration/rollback, operations, blast radius, and reversibility.
|
|
76
|
+
- Prefer the simplest design that satisfies the measured/current requirements while leaving a credible path to change.
|
|
77
|
+
- If the decision is cross-cutting and expensive to revisit, record a short ADR (when the project has `refs.decisions`) with context, decision, consequences, and a **revisit trigger**.
|
|
78
|
+
- Turn measurable architectural characteristics into `fitness` checks.
|
|
79
|
+
|
|
80
|
+
Architecture is not a diagram count or a collection of named patterns. It is the set of consequential boundaries and trade-offs that shape future change. Preserve **conceptual integrity**: prefer a small, coherent set of concepts and boundaries to locally clever exceptions that make every feature require a new mental model.
|
|
81
|
+
|
|
82
|
+
## Structure code so change stays local
|
|
83
|
+
<!-- keelson: id=engineer.structure | without: interfaces mirror frameworks and databases, callers know implementation details, and a small product change fans out across unrelated modules | sunset: never -->
|
|
84
|
+
|
|
85
|
+
- **Hide complexity.** Prefer a small interface over a deep implementation to many shallow wrappers. A module is good when callers need to know less.
|
|
86
|
+
- **Protect policy from volatile details.** Keep domain/use-case decisions from depending directly on framework, transport, database, or vendor-specific shapes when a real boundary makes substitution/testing cheaper.
|
|
87
|
+
- **Put things that change together close together.** A recurring one-feature/five-directory diff is evidence that the boundary is wrong.
|
|
88
|
+
- **Use domain boundaries.** When the same word has different meanings or invariants in two areas, use `model.md` to make the bounded contexts and translation explicit.
|
|
89
|
+
- **Patterns are vocabulary, not goals.** Name a pattern only after the problem already has the shape the pattern solves.
|
|
90
|
+
- **New infrastructure must name its pressure.** A new queue, cache, service, datastore, framework, protocol, or abstraction needs a current constraint, measurement, or failure mode that requires it.
|
|
91
|
+
|
|
92
|
+
## Evolve existing systems safely
|
|
93
|
+
<!-- keelson: id=engineer.evolution | without: unclear legacy behavior is rewritten in one jump, regressions are discovered after cutover, and modernization risk is concentrated into a single release | sunset: never -->
|
|
94
|
+
|
|
95
|
+
For existing/legacy code: **characterize → find a seam → make a small behavior-preserving refactor → verify → change behavior**. Refactoring is not the behavior change; it creates a safer shape for the behavior change.
|
|
96
|
+
|
|
97
|
+
For replacements that cannot safely land at once, prefer parallel change / branch by abstraction or an incremental strangler-style path: old and new coexist behind a controlled boundary while traffic/data/callers move gradually. Make rollback or reverse migration explicit when the risk warrants it.
|
|
98
|
+
|
|
99
|
+
For greenfield integration, a thin tracer bullet should prove one complete path before broad horizontal construction. Avoid a big-bang rewrite unless the owner accepts the cutover risk and there is evidence that incremental migration is materially worse.
|
|
100
|
+
|
|
101
|
+
**Second-system check:** replacing a painful system is not permission to add every deferred feature, abstraction, or platform idea at once. Keep the replacement bounded to its outcome; unrelated wishlist items become separate changes unless acceptance truly depends on them.
|
|
102
|
+
|
|
103
|
+
## Make durable quality executable
|
|
104
|
+
<!-- keelson: id=engineer.fitness | without: architecture quality survives only while reviewers remember prose, so the same constraint is rediscovered and violated repeatedly | sunset: never -->
|
|
105
|
+
|
|
106
|
+
“Fast”, “reliable”, “secure”, and “scalable” are not executable requirements. Give the quality a scope and response measure, then put it in the spec. When a command can test it, add it to `config.yaml → check` with `kind: fitness`.
|
|
107
|
+
|
|
108
|
+
Fitness checks protect the **important characteristic**, not a favorite implementation shape. A dependency-direction check may be correct when that boundary protects policy; “must have five layers” is not a useful fitness function unless those layers themselves are the requirement.
|
|
109
|
+
|
|
110
|
+
Repeated review comments are evidence that either the design should be simplified or the invariant should become an automated check.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Frontend delivery and iteration
|
|
2
|
+
|
|
3
|
+
Keep responsive behavior, performance and visual verification attached to the same real journey.
|
|
4
|
+
|
|
5
|
+
## Adapt to actual conditions
|
|
6
|
+
<!-- keelson: id=frontend-delivery.adaptation | without: One fixed screenshot conceals overflow and unreachable mobile controls | sunset: never -->
|
|
7
|
+
|
|
8
|
+
Check required wide, narrow and intermediate widths, then resize to locate where content actually fails. Choose breakpoints from that failure, not only device names. Preserve meaningful content and reading order rather than hiding the difficult part on mobile.
|
|
9
|
+
|
|
10
|
+
Inspect wrapping, scrolling regions, sticky/fixed surfaces, touch reach and viewport height. Tables may intentionally scroll if relationships and scroll affordances remain clear; unexpected page overflow is a defect. Where applicable test zoom, landscape, mobile keyboard, pointer and keyboard input. Primary actions and error messages must remain reachable. Recheck real long/empty/dense content at each affected layout.
|
|
11
|
+
|
|
12
|
+
## Measure the affected journey
|
|
13
|
+
<!-- keelson: id=frontend-delivery.performance | without: Speculative optimization adds mechanisms without reducing user wait | sunset: never -->
|
|
14
|
+
|
|
15
|
+
Record the path, device/network conditions, measurement method and relevant existing budget before optimizing. Locate the dominant source: downloads, fonts, images, rendering, event handlers, long lists or repeated requests. Use available project tooling rather than adding a framework for appearances.
|
|
16
|
+
|
|
17
|
+
Make the smallest supported improvement, such as correctly sized images with dimensions, loading noncritical resources later, reducing repeated work or splitting a measured heavy path. Remeasure under comparable conditions and confirm correctness and interaction quality. Do not present one development-machine sample as a universal improvement or trade away accessible content to reduce a number.
|
|
18
|
+
|
|
19
|
+
## Extract and document what is stable
|
|
20
|
+
<!-- keelson: id=frontend-delivery.system | without: One-off abstractions proliferate or documented design drifts from code | sunset: never -->
|
|
21
|
+
|
|
22
|
+
For extract, first find real repeated usage and its behavioral differences. Consolidate stable semantic tokens and components using the current stack, naming and ownership boundaries. Preserve public props, responsive behavior, accessibility and exceptional states. Migrate representative call sites and test them before expanding. Do not abstract a single occurrence or create universal components with dozens of unrelated switches.
|
|
23
|
+
|
|
24
|
+
For document, inspect actual CSS/theme files and representative components. Record token roles, typography, spacing, layout, states, accessibility patterns and examples in existing project docs; link to code rather than duplicate everything. Mark proposals separately from observed conventions. Correct the docs after implementation and keep only decisions that future work needs.
|
|
25
|
+
|
|
26
|
+
## Explore and iterate deliberately
|
|
27
|
+
<!-- keelson: id=frontend-delivery.iteration | without: Variants differ only in color or iteration continues without a task-based decision | sunset: never -->
|
|
28
|
+
|
|
29
|
+
For explore, use the same real content and task to compare a few materially different compositions or interaction approaches only when uncertainty justifies it. Name what each improves and sacrifices. Use code prototypes or image tools according to the question; do not treat an image as working software. Implement the selected direction within authorization; ask only when an unresolved choice belongs to the owner.
|
|
30
|
+
|
|
31
|
+
For iterate, inspect the rendered surface, identify one high-impact hypothesis, change a coherent area, reload and compare. Preserve application state where practical and check neighboring states. Stop when acceptance is met rather than chasing endless cosmetic variants. Temporary branches, prototypes and generated assets are owned task artifacts; retain the chosen deliverable and needed evidence, remove only disposable artifacts created for this work.
|
|
32
|
+
|
|
33
|
+
## Close the browser loop
|
|
34
|
+
<!-- keelson: id=frontend-delivery.browser | without: Code passes while browser-only visual and interaction failures ship | sunset: never -->
|
|
35
|
+
|
|
36
|
+
For interface changes or visual/interaction conclusions, use the host's browser tools or the project's existing browser tests to open the running app. Confirm the intended route and resources actually loaded; inspect captured screenshots; execute the primary action and relevant recovery. Check related console/network failures. Keep route, viewport, representative data, steps, result and enough screenshots or test records to reproduce the observation.
|
|
37
|
+
|
|
38
|
+
After a repair, reload and repeat the affected scenario; earlier images cannot prove the new state. Visual inspection, interaction runs and automated checks are distinct evidence. Record them through the existing verification workflow without treating a printed brief as a check result. If tools/services are unavailable, continue independent checks, identify unverified scenarios and give exact follow-up steps; never mark browser acceptance as passed. Remove disposable task outputs at delivery and preserve evidence needed for review.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Interaction and content
|
|
2
|
+
|
|
3
|
+
Work from the actual user journey and data lifecycle. Cover the states that exist in this flow without inventing unrelated features.
|
|
4
|
+
|
|
5
|
+
## Define states and recovery
|
|
6
|
+
<!-- keelson: id=frontend-interaction.states | without: The happy path works but errors lose input or imply false success | sunset: never -->
|
|
7
|
+
|
|
8
|
+
For each affected control or region, identify applicable initial, loading, empty, partial, success, error, disabled and read-only states. Explain what actions remain available and which transition changes the state. Distinguish permissions from transient failure and absence of content from a filter with no matches.
|
|
9
|
+
|
|
10
|
+
Bind save feedback to real request results. Prevent duplicate side effects during submission, preserve recoverable input, and handle late/out-of-order responses using existing project patterns. Retry, cancel and back must not silently discard work. Simulate slow, offline, failed and interrupted paths where relevant. Do not create optimistic success without a recovery contract. Error copy should explain the problem, impact and a feasible next action; never expose secrets in diagnostics.
|
|
11
|
+
|
|
12
|
+
## Make controls operable
|
|
13
|
+
<!-- keelson: id=frontend-interaction.controls | without: Mouse demos pass while keyboard, touch or assistive use fails | sunset: never -->
|
|
14
|
+
|
|
15
|
+
Prefer semantically correct native elements and established project components. Controls need clear accessible names; inputs need persistent associated labels and connected help/error messages. A placeholder is not a label. Do not make essential actions depend on hover or color alone.
|
|
16
|
+
|
|
17
|
+
Actually test tab order, visible focus, keyboard submission and relevant popovers/dialogs. Opening and closing a modal must manage focus appropriately; hidden controls must not remain interactive. Validate without discarding input and help the user locate the failing field. Check dynamic feedback is available to assistive technology through the project's established pattern. Destructive actions need confirmation or recovery proportional to their real consequences; routine actions do not need extra permission dialogs.
|
|
18
|
+
|
|
19
|
+
## Clarify copy and first use
|
|
20
|
+
<!-- keelson: id=frontend-interaction.content | without: Users cannot infer what controls mean or how to reach a useful outcome | sunset: never -->
|
|
21
|
+
|
|
22
|
+
Use action verbs on buttons, orienting headings and only necessary constraints in supporting copy. Use the product's vocabulary rather than internal implementation terms. Replace vague failure messages with specific recovery. Explain why an action is unavailable when the reason is not apparent.
|
|
23
|
+
|
|
24
|
+
For onboard, start with the first useful task. Distinguish not-yet-created, no-results, no-access and failed-loading empty states and offer the correct next step. Teach at the moment of need; allow nonessential guidance to be skipped. Do not add a mandatory tour or welcome modal by default. Preserve user data during examples and never imply sample content belongs to a real customer.
|
|
25
|
+
|
|
26
|
+
## Apply content and language pressure
|
|
27
|
+
<!-- keelson: id=frontend-interaction.locale | without: Translations and real values break layout or change meaning | sunset: never -->
|
|
28
|
+
|
|
29
|
+
Use the project's localization mechanism. Avoid constructing translated sentences from fragments. For supported locales, check longer translations, mixed scripts, plurals, number/date/timezone formatting and writing direction. Prefer logical layout properties when bidirectional support is required.
|
|
30
|
+
|
|
31
|
+
Exercise long names, long error messages, absent data, large values and content that cannot naturally wrap. Preserve task context across locale changes and asset failures. Do not impose arbitrary input limits just because the demo is short. State which locales and directions were actually checked; avoid claiming coverage from source inspection alone.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Frontend review and finishing
|
|
2
|
+
|
|
3
|
+
Audit finds observable failures; critique evaluates task clarity and design choices; polish fixes scoped inconsistencies and verifies the result.
|
|
4
|
+
|
|
5
|
+
## Observe the running interface
|
|
6
|
+
<!-- keelson: id=frontend-review.observe | without: Source inspection is mistaken for seeing the rendered experience | sunset: never -->
|
|
7
|
+
|
|
8
|
+
Run the app using the project's normal command. Record route, viewport, content and state; open the page and inspect the screenshot yourself before forming visual conclusions. Follow the primary journey and relevant keyboard and narrow-screen paths. Notice what attracts attention first, how the next action is understood, and whether feedback and recovery match reality.
|
|
9
|
+
|
|
10
|
+
For audit, inspect semantics, names/labels, keyboard/focus, contrast, state recovery, responsive behavior and relevant runtime issues. For critique, explain hierarchy, grouping, information order, density, brand expression and how those choices affect the task. Distinguish observations, hypotheses and taste. Review-only requests produce findings without silently editing files.
|
|
11
|
+
|
|
12
|
+
A screenshot establishes one rendered state, not working interactions. A successful capture is not image review. Automated scans identify some failures and still require manual keyboard, visual and task checks. Do not invent findings to fill a checklist.
|
|
13
|
+
|
|
14
|
+
## Make findings actionable
|
|
15
|
+
<!-- keelson: id=frontend-review.findings | without: Subjective adjectives leave no reproducible problem or repair priority | sunset: never -->
|
|
16
|
+
|
|
17
|
+
For each material finding give location and trigger, observed behavior, user impact, evidence, and the smallest useful repair. Prioritize blocked tasks, lost work and misleading state first; then operability, comprehension, hierarchy and consistency; finish with decoration. Do not produce a score without a defined basis.
|
|
18
|
+
|
|
19
|
+
Example: “After a failed save, the button says Saved. Users may leave with unsaved changes. Bind feedback to the server result, preserve inputs and expose retry.” A specific before/after scenario is more useful than “make it intuitive.”
|
|
20
|
+
|
|
21
|
+
## Polish without broadening scope
|
|
22
|
+
<!-- keelson: id=frontend-review.finish | without: A finishing pass becomes a redesign or decorates unresolved failures | sunset: never -->
|
|
23
|
+
|
|
24
|
+
Once the journey works, inspect alignment, spacing rhythm, type roles, icon sizing/baselines, control heights, semantic color, hover/focus/pressed/disabled states and content consistency. Use existing tokens; remove accidental one-off values rather than normalizing intentional variation. Fix truncation, unstable loading and vague error copy before micro-decoration.
|
|
25
|
+
|
|
26
|
+
Check the densest and sparsest real content, not only the perfect demo. Keep an authorized local fix local. Recheck adjacent states and components that share the changed token.
|
|
27
|
+
|
|
28
|
+
## Recheck the same scenario
|
|
29
|
+
<!-- keelson: id=frontend-review.acceptance | without: Passing builds are reported as passing visual acceptance | sunset: never -->
|
|
30
|
+
|
|
31
|
+
Repeat the original route, viewport, data and state after changes. Compare rendered images for visual changes and execute the actual action for behavior changes. Reuse automation to protect stable contracts. Capture evidence after the last relevant edit.
|
|
32
|
+
|
|
33
|
+
Report separately: visual observations, interactions exercised, automated checks, and unverified scope. If a browser or required service is unavailable, name the blocked scenarios and explicitly report browser visual/interaction verification as not performed. Continue independent work; never convert unavailable evidence into a pass or lower acceptance to make a completion gate green.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Visual craft
|
|
2
|
+
|
|
3
|
+
Choose expression from the product, content and task. Existing design decisions take precedence over generic styling preferences.
|
|
4
|
+
|
|
5
|
+
## Compose before decorating
|
|
6
|
+
<!-- keelson: id=frontend-visual.hierarchy | without: Every element competes for attention and repeated containers hide relationships | sunset: never -->
|
|
7
|
+
|
|
8
|
+
Rank content importance before choosing size, placement, alignment, spacing or containers. Group related information; separate distinct topics. Make the primary action easy to find without amplifying every action. A dense operational tool and a reading page need different rhythms.
|
|
9
|
+
|
|
10
|
+
For layout, define a clear reading order, consistent alignment and a small spacing scale; test real narrow and wide content. For simplify, remove repeated labels, nested decoration and unnecessary decisions while preserving essential information and discoverability. For bolder, strengthen one meaningful focal point through scale, contrast, composition or imagery. For quieter, reduce competing emphasis and ornament without erasing hierarchy or brand. Do not default every section to a card or every hero to a centered headline plus badges.
|
|
11
|
+
|
|
12
|
+
## Typeset real content
|
|
13
|
+
<!-- keelson: id=frontend-visual.typography | without: Demo headings look polished while body copy and multilingual data fail | sunset: never -->
|
|
14
|
+
|
|
15
|
+
Reuse project fonts and define a limited set of roles for headings, body, labels, supporting text and data. Tune size, weight, line height and line length together. Do not create hierarchy by enlarging all text. Use font weights that actually exist; choose a fallback that keeps content readable while assets load.
|
|
16
|
+
|
|
17
|
+
Check long headings, expanded button labels, mixed scripts, numeric columns, missing glyphs and font loading shifts. Match numeric alignment to the task. Essential content must remain understandable; truncation needs a usable route to full content. Avoid hard-coded heights that clip text at zoom. Load only needed font assets and respect the project's delivery constraints.
|
|
18
|
+
|
|
19
|
+
## Give color and imagery a role
|
|
20
|
+
<!-- keelson: id=frontend-visual.color | without: Decoration undermines readability, state recognition and product truth | sunset: never -->
|
|
21
|
+
|
|
22
|
+
Use semantic tokens for text, surfaces, borders, interaction, status and accent. Test actual foreground/background combinations including interactive states; color cannot be the only signal for error, success or selection. Respect existing brand colors while correcting inaccessible combinations. Test other themes only when supported or requested.
|
|
23
|
+
|
|
24
|
+
Choose imagery that explains product or content. Inspect crop, focal point, aspect ratio, sharpness, missing assets and loading layout. Decorative images should not add redundant speech; informative images need an equivalent accessible description. Reuse licensed project assets or generate new ones when appropriate and supported. Never invent customers, certifications, reviews or product outcomes to fill a layout.
|
|
25
|
+
|
|
26
|
+
## Use motion and delight with purpose
|
|
27
|
+
<!-- keelson: id=frontend-visual.motion | without: Animation delays actions and reduced motion removes essential feedback | sunset: never -->
|
|
28
|
+
|
|
29
|
+
Name what each animation explains: feedback, spatial continuity, progress or a meaningful state transition. Keep it interruptible and responsive to rapid repeated input. Prefer compositor-friendly changes when they fit the effect; do not animate every property by default. Avoid layout jumps, delayed access to essential content and effects that block the primary task.
|
|
30
|
+
|
|
31
|
+
Test reduced-motion preferences, cancellation, rapid toggling and entrance/exit paths. Reduced motion must still communicate result and error. For delight, add one context-appropriate detail that rewards real progress; avoid fake progress, surprise sound, forced celebration or distracting loops. Expressive effects must survive low-end conditions and preserve controls and reading order.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Frontend design
|
|
2
|
+
|
|
3
|
+
Use for creating, improving, diagnosing or verifying an interface people see and operate. Keep the existing change lifecycle; add design judgment and observable interface acceptance.
|
|
4
|
+
|
|
5
|
+
## Route by the problem
|
|
6
|
+
<!-- keelson: id=frontend.routing | without: Small UI fixes turn into broad redesigns and every request loads all guidance | sunset: never -->
|
|
7
|
+
|
|
8
|
+
Read the affected screen, neighboring screens, components and tokens first. Distinguish a new surface, an extension of an existing system, a diagnosis and a local fix. Load only the relevant reference:
|
|
9
|
+
|
|
10
|
+
| Need | Reference | Design actions |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| Diagnose, prioritize, verify | `frontend-review.md` | audit, critique, polish |
|
|
13
|
+
| Hierarchy, typography, color, layout, imagery, motion | `frontend-visual.md` | typeset, color, layout, animate, simplify, bolder, quieter, delight |
|
|
14
|
+
| Forms, feedback, recovery, copy, first use, languages | `frontend-interaction.md` | harden, clarify, onboard |
|
|
15
|
+
| Devices, performance, reusable systems, visual iteration | `frontend-delivery.md` | adapt, optimize, extract, document, explore, iterate |
|
|
16
|
+
|
|
17
|
+
`keelson design` lists focused action briefs; `keelson design <action> [target]` prepares instructions for the host agent. It does not execute an audit, open a browser or edit files. Natural-language requests use the same routing without requiring users to memorize commands. Execute only sections triggered by the selected action and original request. Planning, review and documentation do not implicitly authorize product-code changes. Browser checks apply to actual interface changes or visual/interaction conclusions; source-only documentation must state that basis. For build, start with the task below and load visual/interaction guidance as needed. A local bug goes directly to its narrow fix and regression.
|
|
18
|
+
|
|
19
|
+
## Establish a concrete direction
|
|
20
|
+
<!-- keelson: id=frontend.direction | without: Decoration replaces a coherent user task and visual hierarchy | sunset: never -->
|
|
21
|
+
|
|
22
|
+
Infer audience, primary job, key content, operating conditions and brand constraints from the request and project. State one concrete design intention, such as “help frequent reviewers spot exceptions and resolve them in the list.” Reuse settled answers; ask only for a material missing product decision.
|
|
23
|
+
|
|
24
|
+
Preserve an existing visual system unless an observed problem requires changing it. For a new surface, choose a coherent composition that fits its content; do not default to a particular font, gradient, card grid or oversized hero. Translate “bolder,” “quieter,” or “premium” into an observable change in emphasis, grouping, density or expression. Reversible design choices belong to agent judgment within the user's authorization.
|
|
25
|
+
|
|
26
|
+
Keep durable product facts in existing intent/docs; record stable visual conventions in existing design docs or a scoped rule only when future work needs them. A one-off page does not need another mandatory document hierarchy.
|
|
27
|
+
|
|
28
|
+
## Build one real path
|
|
29
|
+
<!-- keelson: id=frontend.slice | without: A polished first screen hides incomplete states and unusable controls | sunset: never -->
|
|
30
|
+
|
|
31
|
+
For implementation tasks, implement a representative user journey before expanding to more screens. Use real or explicitly representative content, including long text, missing values and realistic data volume. Prioritize task blockers and comprehension, then hierarchy and responsiveness, then decoration. Every visible control must work, explain its unavailable state, or be removed within scope.
|
|
32
|
+
|
|
33
|
+
Express acceptance in existing change artifacts: who, in what state and environment, performs what action, observes what outcome, and how it will be checked. Reuse project components, utilities and test facilities. Do not add a library merely to demonstrate sophistication. Complete with `frontend-review.md` and the browser loop in `frontend-delivery.md`; code checks alone cannot establish visual quality.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Stopping and resuming
|
|
2
|
+
|
|
3
|
+
The line between "did one task" and "kept a project moving" is whether the next session, the next person, or the next model can continue without redoing or undoing work. Two files carry that: `NOW.md` for the project, `changes/<name>/handoff.md` for a change that crosses sessions.
|
|
4
|
+
|
|
5
|
+
## What goes where
|
|
6
|
+
<!-- keelson: id=handoff.split | without: session logs are either committed as noise or everything is gitignored and the team has no continuation record | sunset: never -->
|
|
7
|
+
|
|
8
|
+
| Information | Lives in |
|
|
9
|
+
|---|---|
|
|
10
|
+
| What is in flight across the project, what is blocked, the next step | `NOW.md`, committed, rewritten in full |
|
|
11
|
+
| Continuation state of one change: confirmed decisions, done slices, open and blocked items, ruled-out assumptions, next step, verification status | `changes/<name>/handoff.md`, committed |
|
|
12
|
+
| Signed check records and referenced output | `changes/<name>/ledger.jsonl` + `evidence/`, retained with the change; review output before sharing |
|
|
13
|
+
| Private signing keys, command trust, session scratch | Git's private `keelson-runtime` directory, or a user cache outside non-Git projects; never committed |
|
|
14
|
+
|
|
15
|
+
Anything a colleague on another machine would need is not local state.
|
|
16
|
+
|
|
17
|
+
## Writing a handoff
|
|
18
|
+
<!-- keelson: id=handoff.write | without: the next session starts from git archaeology; rejected assumptions are retried; unverified work is treated as verified | sunset: never -->
|
|
19
|
+
|
|
20
|
+
Run `keelson handoff <name>` (creates or re-stamps `handoff.md` with the commit, time, and author) and fill the six sections. It is a current-state summary: overwrite it, never append a diary.
|
|
21
|
+
|
|
22
|
+
- **Goal and confirmed decisions** — one paragraph, present tense, linking `change.md` rather than repeating it.
|
|
23
|
+
- **Done** — slices or tasks complete and verified, with the `Verify:` that proves it.
|
|
24
|
+
- **Open and blocked** — each item with what it blocks.
|
|
25
|
+
- **Ruled out** — assumptions or approaches rejected, with the evidence, so nobody retries them.
|
|
26
|
+
- **Next step** — the first concrete action, small enough to start cold.
|
|
27
|
+
- **Verification** — the last `Verify:` (command, exit code, tree) and what has not been checked.
|
|
28
|
+
|
|
29
|
+
Then rewrite `NOW.md` so the project view agrees. The session-start hook prints the handoff's next step when the next session opens.
|
|
30
|
+
|
|
31
|
+
## Resuming
|
|
32
|
+
<!-- keelson: id=handoff.resume | without: agent executes a stale handoff against a moved worktree, or "cleans up" uncommitted work the owner wanted kept | sunset: never -->
|
|
33
|
+
|
|
34
|
+
1. `keelson status`: work, verification, and release state, whether HEAD moved since the handoff, uncommitted files.
|
|
35
|
+
2. If HEAD moved or the tree is dirty, read what changed (`git log`, `git diff`) before trusting the handoff; other work may have landed, and shared contracts may have shifted.
|
|
36
|
+
3. Never delete or reset uncommitted changes to "start clean". Ask, or work around them.
|
|
37
|
+
4. Re-run `keelson check --record` before building on prior verification; it is stale by definition after any edit.
|
|
38
|
+
5. Continue from **Next step**; update `handoff.md` and `NOW.md` when you stop again.
|
|
39
|
+
|
|
40
|
+
## NOW.md
|
|
41
|
+
<!-- keelson: id=handoff.now | without: the next session starts blind and re-derives state from git | sunset: never -->
|
|
42
|
+
|
|
43
|
+
Rewrite the whole file, present tense, three short parts: what is active (or "nothing in flight"), what is blocked or uncertain (including "not yet checked: …"), the next concrete step. `keelson land --now "<text>"` writes it at landing. Pausing, being blocked, and cancelling are normal states; write them as they are rather than forcing a change to "done" to close a session.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Evolving the harness
|
|
2
|
+
|
|
3
|
+
A useful harness does two jobs: it makes the desired path easier **before** the agent acts, and it gives the agent cheap signals to self-correct **after** it acts. The goal is not to script the model. The goal is to move stable engineering knowledge out of chat and into the smallest control that can reliably carry it.
|
|
4
|
+
|
|
5
|
+
## Enforce invariants, not implementation taste
|
|
6
|
+
<!-- keelson: id=harness.invariants | without: prose micromanages implementation details, goes stale with the code, and agents satisfy the recipe while violating the real boundary | sunset: never -->
|
|
7
|
+
|
|
8
|
+
Write the durable thing that must remain true: dependency direction, API compatibility, data validation at a boundary, an acceptance condition, a latency budget. Do not prescribe a library, class layout, or sequence of edits unless that choice is itself part of the contract.
|
|
9
|
+
|
|
10
|
+
Route the invariant to the narrowest authority:
|
|
11
|
+
|
|
12
|
+
- observable product behaviour → capability spec;
|
|
13
|
+
- path-specific engineering convention → `.keelson/rules/`;
|
|
14
|
+
- measurable invariant → `config.yaml → check` with `kind: fitness`;
|
|
15
|
+
- temporary implementation choice → `change.md`, then delete it when the change lands.
|
|
16
|
+
|
|
17
|
+
A good mechanical check reports **what invariant failed and where**, then lets the agent choose the repair.
|
|
18
|
+
|
|
19
|
+
## Put each control at the cheapest useful point
|
|
20
|
+
<!-- keelson: id=harness.control-loop | without: everything becomes always-on prose or a late CI surprise, wasting context before the edit and feedback time after it | sunset: never -->
|
|
21
|
+
|
|
22
|
+
| | Before generation (feedforward) | After generation (feedback) |
|
|
23
|
+
|---|---|---|
|
|
24
|
+
| inferential | resident block, skill, scoped rules, specs | fresh-reader review, semantic review |
|
|
25
|
+
| computational | codemods, typed APIs, generators | lint, typecheck, unit/integration tests, structural/fitness checks |
|
|
26
|
+
|
|
27
|
+
Keep cheap deterministic controls close to the edit. Run targeted checks inside the BUILD loop, the configured full check set before completion, and slower/expensive review only when risk justifies it. Do not duplicate the same rule across resident instructions, skill prose, a rule file, and CI; choose one source of truth and point to it.
|
|
28
|
+
|
|
29
|
+
## Promote repeated mistakes instead of growing prompts
|
|
30
|
+
<!-- keelson: id=harness.promotion | without: recurring mistakes live as chat folklore, while every incident adds more prose and the always-on context grows without becoming more enforceable | sunset: when project-specific controls can no longer be traced to a live invariant or recurring failure -->
|
|
31
|
+
|
|
32
|
+
Use this promotion ladder:
|
|
33
|
+
|
|
34
|
+
1. **First occurrence:** fix the defect; record the root cause if it reached verification.
|
|
35
|
+
2. **Repeated class of failure:** run `keelson retro`; name the stable invariant the failures have in common.
|
|
36
|
+
3. **Semantic prevention:** add or tighten the narrowest spec/rule/reference that helps the agent choose correctly before editing.
|
|
37
|
+
4. **Deterministic prevention:** if a script can detect the violation reliably, make it a `fitness` check; if it is fast enough, wire it into the normal local/CI path.
|
|
38
|
+
5. **After automation proves reliable:** shrink or remove prose that merely repeats what the check now enforces.
|
|
39
|
+
|
|
40
|
+
Do not automate one-off taste disagreements. Promotion is justified when the failure is recurring, costly, and has a stable signal.
|
|
41
|
+
|
|
42
|
+
## Preserve failure attribution and regression power
|
|
43
|
+
<!-- keelson: id=harness.attribution | without: the agent fixes failures that pre-date its change or records green checks that would also pass with the bug restored | sunset: never -->
|
|
44
|
+
|
|
45
|
+
Before risky work, establish a targeted baseline when otherwise you could not tell whether a failure is pre-existing. During implementation, prefer the smallest check that localizes the current slice. For a bug fix, keep a negative regression check: with the fix removed, the new test must fail. At completion, run the fresh configured check set against the exact tree you are claiming about.
|
|
46
|
+
|
|
47
|
+
A failing baseline is not permission to ignore the suite. Record the pre-existing failure, avoid widening it, and verify the changed surface independently until the baseline can be repaired.
|
|
48
|
+
|
|
49
|
+
## Keep the harness revisable
|
|
50
|
+
<!-- keelson: id=harness.adaptive | without: the repository accumulates workarounds for old model limitations and every future agent pays their context and process cost | sunset: when every non-permanent control has an explicit removal trigger and retro is run regularly -->
|
|
51
|
+
|
|
52
|
+
Every harness rule encodes an assumption about what the agent or project cannot safely do unaided. Re-test those assumptions. Prefer controls tied to project invariants over controls tied to one model's current quirks. When a control exists only to compensate for observed agent behaviour, give it a sunset condition or measurable reason to keep it.
|
|
53
|
+
|
|
54
|
+
`keelson retro` is the maintenance loop: use evidence from ledgers and failures to **add, strengthen, weaken, or remove** guidance. A mature harness gets more precise, not merely larger.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Adaptive decision interviews
|
|
2
|
+
|
|
3
|
+
Keelson users do not need software-architecture vocabulary. Interviewing is hidden control logic: discover only decisions the owner truly owns, make each one easy to answer, then return to building. Ordinary work is **not** a questionnaire; explicit “stress-test this” requests are deeper stress tests of the same decision tree.
|
|
4
|
+
|
|
5
|
+
## Question protocol: earn the interruption
|
|
6
|
+
<!-- keelson: id=interview.protocol | without: the agent asks unnecessary questions, hands implementation choices to the owner, or interrupts without knowing what the answer changes | sunset: never -->
|
|
7
|
+
|
|
8
|
+
Before asking, answer internally:
|
|
9
|
+
|
|
10
|
+
1. **Consequence** — what user-visible behavior, acceptance boundary, risk, cost, compatibility promise, or durable commitment changes with the answer?
|
|
11
|
+
2. **Ownership** — is the answer owned by repository/reality, Agent engineering judgment, or owner intent/risk tolerance?
|
|
12
|
+
3. **Discoverability** — can code, tests, docs, telemetry, official docs, or a small experiment answer it?
|
|
13
|
+
4. **Reversibility** — if the default is wrong, is recovery cheap and local or expensive/irreversible?
|
|
14
|
+
5. **Information value** — is this the unresolved choice most likely to change the next safe slice?
|
|
15
|
+
6. **Default** — what grounded answer would you choose if the owner said “use your judgment”?
|
|
16
|
+
|
|
17
|
+
If you cannot name a material consequence, or the owner does not own the answer, **do not ask**. Investigate, choose the reversible default, or defer it to a later slice.
|
|
18
|
+
|
|
19
|
+
## Blindspot pass before the first question
|
|
20
|
+
<!-- keelson: id=interview.blindspots | without: the interview handles only unknowns the user already knows about and misses domain-specific failure modes | sunset: never -->
|
|
21
|
+
|
|
22
|
+
Do one compact risk-triggered pass before interviewing. Load only the rows triggered in `design-lenses.md`; inspect the repository and existing contracts first. Look for unknown unknowns that commonly change the design: destructive data semantics, permission boundaries, external compatibility, duplicate/retry behavior, migration/rollback, failure recovery, accessibility, measured performance/cost, or AI nondeterminism.
|
|
23
|
+
|
|
24
|
+
A blindspot does **not** automatically become a question. Route it to an existing guarantee, an engineering default, an experiment, an acceptance/evidence case, or an owner decision. Ask only the last category.
|
|
25
|
+
|
|
26
|
+
## One decision, recognition over recall
|
|
27
|
+
<!-- keelson: id=interview.one-at-a-time | without: a wall of questions overloads the owner, while open-ended jargon questions force beginners to invent architecture preferences | sunset: never -->
|
|
28
|
+
|
|
29
|
+
Read `keelson ask list --json` before asking. Never repeat a settled answer without new evidence and `ask reopen <id> --reason`. Ask at most three independent, ready user-owned decisions in one round; dependent choices wait for their prerequisite. Use `ask add`, `settle`, `assume`, and `frontier` to persist ownership, answer and basis. Irreversible decisions require settlement, not assumptions. Prefer a concrete scenario and recognition over recall:
|
|
30
|
+
|
|
31
|
+
- describe the situation in the owner’s language;
|
|
32
|
+
- give 2–4 **materially different outcomes**; when useful, attach one concise **Engineering:** consequence to each option instead of making the owner infer the implementation;
|
|
33
|
+
- recommend one default and give the single most important reason;
|
|
34
|
+
- state one meaningful trade-off when it matters;
|
|
35
|
+
- include **“not sure / use your recommendation”** when legitimate;
|
|
36
|
+
- allow free text if none of the options fit.
|
|
37
|
+
|
|
38
|
+
Bad: “Postgres or MongoDB?”
|
|
39
|
+
|
|
40
|
+
Better: “Can one record contain fields that change shape freely between users, or should every record obey one shared schema? I recommend a shared schema unless flexible per-user shapes are a core feature; it keeps validation and migrations simpler. **Engineering:** with the project's existing relational database this is a normal typed table; no new datastore is needed.”
|
|
41
|
+
|
|
42
|
+
Do not make the owner remember earlier context to answer. Briefly restate the fact or constraint that makes this question relevant.
|
|
43
|
+
|
|
44
|
+
## Make the question scannable
|
|
45
|
+
<!-- keelson: id=interview.presentation | without: the right question is buried in prose, recommendations are mistaken for requirements, or the owner cannot see the choices at a glance | sunset: never -->
|
|
46
|
+
|
|
47
|
+
Keep the owner-visible interaction compact. Use this shape when options are useful:
|
|
48
|
+
|
|
49
|
+
**Decision:** <one plain-language question>
|
|
50
|
+
|
|
51
|
+
- A. <observable outcome>
|
|
52
|
+
**Engineering:** <data model / permission / API / operational consequence if material>
|
|
53
|
+
- B. <observable outcome>
|
|
54
|
+
**Engineering:** <material implementation consequence>
|
|
55
|
+
- C. <observable outcome, only if genuinely distinct>
|
|
56
|
+
**Engineering:** <material implementation consequence>
|
|
57
|
+
- Not sure — use your recommendation
|
|
58
|
+
|
|
59
|
+
**Recommended:** <choice>, because <one decisive reason>.
|
|
60
|
+
**Implementation direction:** <reuse the current stack; name the likely concrete components only when they are supported by the repository or genuinely differ by option>.
|
|
61
|
+
|
|
62
|
+
Add a one-sentence “Why now” only when the relevance is not obvious. Do not expose the internal lens checklist, scoring, or chain of reasoning. If the owner asks for an explanation, answer it in normal chat before asking again.
|
|
63
|
+
|
|
64
|
+
## Show enough implementation consequence
|
|
65
|
+
<!-- keelson: id=interview.implementation | without: the owner understands the product choice but cannot tell what it means for the actual system, or technology names are presented without architectural context | sunset: never -->
|
|
66
|
+
|
|
67
|
+
Before naming a technology, inspect the repository's actual stack. The question card should make the engineering consequence concrete without turning into technology shopping:
|
|
68
|
+
|
|
69
|
+
- If the existing stack supports an option, say what changes inside that stack: schema/table, permission model, endpoint/contract, background job, cache, migration, or test surface.
|
|
70
|
+
- If **no new technology is required**, say so explicitly. Do not introduce Redis, Kafka, a new database, a new service, or a framework merely to make the answer look technical.
|
|
71
|
+
- If options genuinely require different architecture, name the likely concrete technology or category and why—for example “existing Postgres + ACL table is enough” versus “team-wide fan-out at this scale would require a queue”.
|
|
72
|
+
- In a greenfield project, state a **likely direction**, not a fake certainty: “relational database such as Postgres”, “object storage”, “queue only if asynchronous fan-out is required”.
|
|
73
|
+
- Prefer implementation consequences the owner can reason about: consistency, migration difficulty, operational cost, failure modes, permissions, and future reversibility.
|
|
74
|
+
|
|
75
|
+
Technology is explanatory context after the product consequence is clear. It is not a substitute for the decision itself.
|
|
76
|
+
|
|
77
|
+
## Dependency order and scope pressure
|
|
78
|
+
<!-- keelson: id=interview.order | without: downstream technology is decided before product boundaries, or the interview expands into speculative future architecture | sunset: never -->
|
|
79
|
+
|
|
80
|
+
Resolve decisions in dependency order:
|
|
81
|
+
|
|
82
|
+
**problem / actor → scope and non-goals → observable behavior → data/permission invariants → external contracts → failure semantics → expensive architecture → implementation details**
|
|
83
|
+
|
|
84
|
+
Ask earlier questions only when they change later branches. Detect grab-bag requests and rabbit holes: separate independent domains, identify which one unlocks the next useful slice, and park speculative future needs instead of designing for them now.
|
|
85
|
+
|
|
86
|
+
A reversible implementation detail never deserves an owner question merely because multiple valid options exist.
|
|
87
|
+
|
|
88
|
+
## Adapt to expertise without profiling
|
|
89
|
+
<!-- keelson: id=interview.adaptive | without: beginners guess jargon, experienced owners get verbose tutorials, or the project stores a fragile beginner/expert label | sunset: never -->
|
|
90
|
+
|
|
91
|
+
Plain-language scenarios are the default for everyone. After the behavior is understood, name the engineering concept in one short phrase when useful. If the owner already uses a term precisely, mirror it and compress the explanation.
|
|
92
|
+
|
|
93
|
+
Never ask users to classify themselves as beginner/intermediate/expert and never persist such a label. Adapt from the current conversation only. `guide: true` adds pedagogy—why the choice matters, the name of the concept, and when to revisit it—but does not add more gates or more mandatory questions.
|
|
94
|
+
|
|
95
|
+
## “I don’t know” is a valid routing answer
|
|
96
|
+
<!-- keelson: id=interview.uncertain | without: users invent technical preferences, repeated questions create frustration, or work blocks on a choice a prototype/default could settle | sunset: never -->
|
|
97
|
+
|
|
98
|
+
Treat uncertainty as information:
|
|
99
|
+
|
|
100
|
+
- **Reality-owned** → investigate.
|
|
101
|
+
- **Reversible engineering choice** → follow project precedent or use the recommended default.
|
|
102
|
+
- **User-owned but hard to imagine** → show the smallest example, payload, sketch, comparison, or throwaway prototype.
|
|
103
|
+
- **Performance/cost uncertainty** → measure before adding machinery.
|
|
104
|
+
- **High-impact owner decision still unknown** → block only the slice that truly depends on it.
|
|
105
|
+
- **User asks for explanation instead of answering** → explain first in normal chat; do not immediately re-ask the same card/question.
|
|
106
|
+
|
|
107
|
+
Never turn “I don’t know which technology” into a technology poll. Translate it into the product property or operational constraint that would make the technology choice matter.
|
|
108
|
+
|
|
109
|
+
## Read back, persist the result, and stop
|
|
110
|
+
<!-- keelson: id=interview.stop | without: answers stay trapped in chat, the same decision is asked again, or ordinary work becomes an endless interview | sunset: never -->
|
|
111
|
+
|
|
112
|
+
After an answer, confirm **decision + consequence** in one sentence, persist only the durable result in the owning artifact, and recompute the decision frontier. Do not create a transcript.
|
|
113
|
+
|
|
114
|
+
For ordinary work, stop asking as soon as the next vertical slice has:
|
|
115
|
+
- a clear observable outcome;
|
|
116
|
+
- explicit boundaries/non-goals where needed;
|
|
117
|
+
- no unresolved owner-owned decision that blocks it;
|
|
118
|
+
- an acceptance/evidence path.
|
|
119
|
+
|
|
120
|
+
Questions about later slices remain open without blocking current work. If the owner explicitly asks for a deep stress test, continue through every **material** branch inside the requested boundary, but still reject speculative future branches and low-value implementation trivia.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Integrating and releasing
|
|
2
|
+
|
|
3
|
+
A change is implemented when its slices are verified, integrated when it is on the target branch with its specs folded, and released when a tagged version ships it. These are three states, and Keelson reports them separately.
|
|
4
|
+
|
|
5
|
+
## `keelson land <name>`
|
|
6
|
+
<!-- keelson: id=land.command | without: delta specs never merge, specs stop describing the current system, and unverified or unapproved work is declared integrated | sunset: never -->
|
|
7
|
+
|
|
8
|
+
Run it when the change is integrated (merged, or committed on the mainline in a solo repository). It refuses while any of these hold, and says which:
|
|
9
|
+
|
|
10
|
+
- acceptance items unchecked (task checkboxes are advisory plan state, not landing gates);
|
|
11
|
+
- open questions remain;
|
|
12
|
+
- verification is not-run, failed, partial, or stale (fingerprint differs from the working tree);
|
|
13
|
+
- `(assumed)` decisions exist and `--confirm-assumptions` was not passed — the owner confirms them, not you;
|
|
14
|
+
- the main spec changed since the delta was written and `--accept-drift` was not passed — re-read it, reconcile, then pass the flag;
|
|
15
|
+
- **BREAKING** without a **Rollout** section.
|
|
16
|
+
|
|
17
|
+
Then it merges each delta into the capability spec (ADDED appends, MODIFIED replaces by name, REMOVED deletes), appends the `Decisions` lines, and removes the change directory (`land: fold`, default) or archives it (`land: keep`). `--dry-run` previews all of it. `--force` exists for the owner's explicit decision, never for convenience.
|
|
18
|
+
|
|
19
|
+
Commit the landing together with the last code change, so the specs and the code that satisfies them share a revision. Ledger and handoff stay in git history; `keelson retro` reads them from there.
|
|
20
|
+
|
|
21
|
+
## Code and specs are reviewed together
|
|
22
|
+
<!-- keelson: id=land.same-pr | without: documentation is "caught up" at the end of a milestone, by which time nobody remembers why | sunset: never -->
|
|
23
|
+
|
|
24
|
+
The pull request that changes behaviour carries the delta spec and the decision lines. A reviewer who reads the diff without the spec cannot tell whether a behaviour change was intended.
|
|
25
|
+
|
|
26
|
+
## Collisions
|
|
27
|
+
<!-- keelson: id=land.collisions | without: an older decision or verification is treated as valid after another change moved the contract underneath it | sunset: never -->
|
|
28
|
+
|
|
29
|
+
When another change modified a shared contract, the target branch, or the verification environment, the older change's decisions and evidence may no longer hold. Signals: `keelson status` shared-contract warning, `land` drift refusal, a stale verification after a merge. Response: re-read the moved spec, reconcile the delta, re-run `keelson check --record`, and only then land. Spec merges preview first; they never overwrite silently.
|
|
30
|
+
|
|
31
|
+
## Release state
|
|
32
|
+
<!-- keelson: id=land.release | without: "merged" is reported as "shipped", and a migration or manual step is forgotten | sunset: never -->
|
|
33
|
+
|
|
34
|
+
Release state is derived from git tags: `keelson status` lists changes landed since the last tag as unreleased. A change with a **Rollout** section is not complete until its steps have run; keep them in `NOW.md → Next` until they have. Keelson can remind; it never performs production operations itself.
|
|
35
|
+
|
|
36
|
+
## Reconcile before you archive
|
|
37
|
+
|
|
38
|
+
Landing merges the delta and the decisions. The rest of what the change taught (a new term, a moved responsibility, a quality number, a constraint that can be a check, a defect that deserves a regression test) is routed by `references/reconcile.md`. Do that pass before `keelson land`, so the truth files and the code share the landing commit.
|
|
39
|
+
|
|
40
|
+
## Promote learnings, and file the debt
|
|
41
|
+
<!-- keelson: id=land.promote | without: the same convention is rediscovered in every change; defects found late become folklore instead of checks | sunset: never -->
|
|
42
|
+
|
|
43
|
+
Before closing, ask in one line: did this change reveal a convention worth a rule, a check worth adding to `config.yaml → check`, a contract worth a requirement, or a defect worth a regression test? Prefer, in order: an automated check, a spec requirement, a rule with a scope, then a decision line. A problem that stays a paragraph of prose will be re-learned. Known remaining problems become tracked items with an owner (in the tracker, or `ROADMAP.md → Next`), not a sentence in a summary.
|
|
44
|
+
|
|
45
|
+
## Spec `Decisions` etiquette
|
|
46
|
+
|
|
47
|
+
A decision line is one to three lines, present tense, and names the rejected option: `- messaging: consumers are idempotent; exactly-once delivery rejected because the broker does not provide it`. When a decision is reversed later, rewrite the line and keep a trailing note: `(previously: at-most-once, abandoned after duplicate-notification incident)`. Never let `Decisions` become a changelog. When the code disagrees with a confirmed requirement, report the gap; changing the spec to match the defect needs the owner's decision.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Domain model and shared language
|
|
2
|
+
|
|
3
|
+
A project that lasts collects words, and the same word starts meaning two things while two words mean one. The model layer keeps the vocabulary, the boundaries between parts of the system, and the invariants that hold inside each part.
|
|
4
|
+
|
|
5
|
+
## One word, one meaning
|
|
6
|
+
<!-- keelson: id=model.language | without: "account", "user", "member", and "profile" drift apart across code, specs, and conversation, and every change starts with a translation argument | sunset: never -->
|
|
7
|
+
|
|
8
|
+
Terms that appear in specs, code identifiers, and conversation live in `.keelson/GLOSSARY.md`, one line each: `- Member — a User's identity inside one Workspace; carries the role`. When a request uses a term that is not there, or uses a glossary term differently, settle it before designing. When a term genuinely means different things in different parts of the system, name the part and keep both lines; that boundary is a bounded context, and the two parts talk through an explicit translation rather than a shared table.
|
|
9
|
+
|
|
10
|
+
Specs, rules, and change.md use the glossary term. Code follows it in names; when the code already uses a different word, the change either renames or records the mapping in the glossary line.
|
|
11
|
+
|
|
12
|
+
## Boundaries and invariants
|
|
13
|
+
<!-- keelson: id=model.boundaries | without: modules know too much about each other; a change in one leaks into three, and the spec cannot say who is responsible for what | sunset: never -->
|
|
14
|
+
|
|
15
|
+
Each capability spec answers "what does this part promise the rest of the system" (requirements) and "what may never be false inside it" (invariants: an order total equals the sum of its lines; a revoked link answers 404 on every path). When a change crosses a boundary, the delta names the contract that changes, and the other side's owner sees it in `keelson status` as a shared contract.
|
|
16
|
+
|
|
17
|
+
For architecture constraints, which are not behaviour ("the media pipeline never writes to the permissions table", "every read passes through `canView()`"), use a rule scoped to the paths it governs, and, where possible, a check in `config.yaml → check` that fails when it is broken. A constraint that only lives in prose will be broken by someone who never read it.
|
|
18
|
+
|
|
19
|
+
## Hide what changes
|
|
20
|
+
<!-- keelson: id=model.deep-modules | without: interfaces mirror the current implementation; every internal change becomes an interface change and ripples to callers | sunset: never -->
|
|
21
|
+
|
|
22
|
+
When you design a module or an interface, ask: what does the caller need to know, what complexity can stay behind the interface, what is most likely to change, and does that knowledge already leak into other modules? Prefer a small interface over a deep implementation to many thin modules that expose their internals. File length is not the measure; the number of things a caller must understand is.
|
|
23
|
+
|
|
24
|
+
When a capability's spec keeps growing and its requirements no longer share a purpose, that is the signal for a new capability with its own spec, not for a longer file.
|
|
25
|
+
|
|
26
|
+
## Design it twice, cheaply
|
|
27
|
+
<!-- keelson: id=model.design-twice | without: the first design that comes to mind is built, and its costs are discovered in the code review | sunset: never -->
|
|
28
|
+
|
|
29
|
+
For a spec change, sketch two designs before choosing, in a few lines each under `## Alternatives`: the interface each exposes, what each hides, what each makes hard later. The second sketch is often worse; writing it is how you learn what the first one is paying for. Record the rejected one with its strongest argument.
|