---
phase: 01-framework-kernel-foundation
plan: 03
type: execute
wave: 3
depends_on: ["01-02"]
files_modified:
- internal/build/build.go
- internal/build/manifest.go
- internal/build/scaffold.go
- internal/dev/watch.go
- cmd/summer/main.go
- bonfire/root.go
- bonfire/command.go
- bonfire/output.go
- bonfire/widgets.go
- bonfire/prompts.go
- bonfire/output_test.go
- bonfire/prompts_test.go
- internal/build/build_test.go
- internal/dev/watch_test.go
- examples/hello/plugins/greeter/plugin.go
- go.mod
- go.sum
autonomous: true
requirements: [KERN-04, KERN-09, CLI-01]
must_haves:
truths:
- "D-01 D-03 D-04 D-05: `summer make:plugin` scaffolds a compiling plugin and `summer plugin:add` adds it to the ordered manifest/workspace; `summer build` regenerates imports and a separate app binary."
- "D-14: Spinner, progress, table, ask/confirm/choice/secret prompts and color policy use standard library plus `x/term`, with deterministic non-TTY output."
- "D-15 D-17: Tool and app commands use colon-style names; plugin command metadata, flags, arguments and injected Output are wrapped by the shared cobra kernel."
- "D-16: `summer dev` watches sources/config/manifests, debounces, calls the same build function, restarts the app only after successful build, and prints measured rebuild latency."
artifacts:
- path: internal/build/scaffold.go
provides: Minimal plugin scaffold and manifest/workspace registration
- path: bonfire/widgets.go
provides: Spinner, progress and table rendering
- path: bonfire/prompts.go
provides: Prompt handling and non-TTY fallback
- path: internal/dev/watch.go
provides: Built-in watch rebuild loop
key_links:
- from: cmd/summer/main.go
to: internal/build/scaffold.go
via: `make:plugin` and `plugin:add` tool commands
- from: internal/dev/watch.go
to: internal/build/build.go
via: One shared build function
- from: bonfire/root.go
to: bonfire/output.go
via: Output injection into plugin commands
---
As a framework developer, I can add a plugin, rebuild, see useful CLI output, and keep an app running while editing source, so compiled plugins have a practical development loop.
Purpose: Complete the Phase 1 tool experience around the already bootable hello app.
Output: `make:plugin`, `plugin:add`, rich CLI output and built-in `summer dev` watch loop.
@$HOME/.codex/get-shit-done/workflows/execute-plan.md
@$HOME/.codex/get-shit-done/templates/summary.md
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/REQUIREMENTS.md
@.planning/phases/01-framework-kernel-foundation/01-CONTEXT.md
@.planning/phases/01-framework-kernel-foundation/01-RESEARCH.md
@.planning/phases/01-framework-kernel-foundation/01-VALIDATION.md
@.planning/phases/01-framework-kernel-foundation/01-02-SUMMARY.md
@../modules/summer-bonfire/PLAN.md
Task 1: Add and rebuild a compiling plugin from the tool
internal/build/build.go, internal/build/manifest.go, internal/build/scaffold.go, internal/build/build_test.go, cmd/summer/main.go
internal/build/build.go, internal/build/manifest.go, internal/build/scaffold.go, internal/build/build_test.go, cmd/summer/main.go, examples/hello/summer.yaml, examples/hello/go.mod, examples/hello/plugins.gen.go, examples/hello/plugins/base/plugin.go, go.work, .planning/phases/01-framework-kernel-foundation/01-CONTEXT.md, .planning/phases/01-framework-kernel-foundation/01-RESEARCH.md
Complete D-01/D-03/D-04/D-05 using `summer.yaml` as the sole ordered source of plugin IDs and module paths. `summer make:plugin ` scaffolds `plugins//go.mod` with module path `/plugins/` and `toolchain go1.27.0`, `plugin.go` implementing ID/Requires/Register/Boot and `init(){ party.Register(...) }`, plus an empty `config/` placeholder; no model/migration/controller/command stubs. `summer plugin:add ` reads the module path from that directory's `go.mod`, validates the ID and module path, adds the plugin once to `summer.yaml`, updates the nearest app `go.work` with `go work use`, and updates app `go.mod` as needed for a portable dependency graph. Preserve manifest order and reject conflicting IDs. `summer build` must regenerate both app files from the updated manifest and print elapsed build time; no map iteration controls output. Keep tool source independent of app/plugin imports. Exercise the commands on a temporary copy of `examples/hello` so the permanent testbed stays small.
go test ./internal/build ./cmd/summer && (cd examples/hello && go test ./...)
- `make:plugin golem15.demo` produces a compiling plugin module with only `go.mod`, `plugin.go` and `config/`.
- `plugin:add` adds one manifest entry and workspace module; repeating it is idempotent.
- `summer build` produces byte-stable `main.go` and `plugins.gen.go` from the updated manifest.
- The framework tool has no import of an app-specific plugin package.
A new local plugin can be scaffolded, added and compiled into the hello app.
Task 2: Give tool and plugin commands deterministic rich output
bonfire/root.go, bonfire/command.go, bonfire/output.go, bonfire/widgets.go, bonfire/prompts.go, bonfire/output_test.go, bonfire/prompts_test.go, cmd/summer/main.go, examples/hello/plugins/greeter/plugin.go, go.mod, go.sum
bonfire/root.go, bonfire/command.go, bonfire/output.go, bonfire/widgets.go, bonfire/prompts.go, bonfire/output_test.go, bonfire/prompts_test.go, cmd/summer/main.go, examples/hello/plugins/greeter/plugin.go, go.mod, go.sum, ../modules/summer-bonfire/PLAN.md, .planning/phases/01-framework-kernel-foundation/01-CONTEXT.md, .planning/phases/01-framework-kernel-foundation/01-RESEARCH.md
Implement D-14/D-15/D-17 with stdlib formatting and `golang.org/x/term` v0.46.0 only for terminal capability/raw/password primitives. `bonfire.Output` is constructed once from injected stdin/stdout/stderr and terminal/color policy; the cobra adapter passes `ctx`, parsed `Input`, and that Output to every `bonfire.Command`. Command metadata defines arguments and flags without duplicating root wiring; reject plugin command names without `:`, while kernel tool commands are `make:plugin`, `plugin:add`, `build`, `dev`. Implement braille spinner and gradient progress for TTY, box-drawing table, ask/confirm/choice/secret prompts. For non-TTY: spinner prints one `[...] message`; progress prints `[N/M] pct%` at 10% steps; table is tab-separated; ask/choice/secret read stdin lines; confirm uses its default. `NO_COLOR` or `TERM=dumb` disables ANSI; `FORCE_COLOR` enables it only when neither disable condition is present. `secret` uses `term.ReadPassword` on TTY and a plain stdin line otherwise. Make the hello plugin command exercise table and one prompt without hanging when stdin is closed.
go test ./bonfire ./cmd/summer && (cd examples/hello && go test ./...)
- `summer make:plugin --help` and the app's `greeter:hello --help` are generated through the shared `bonfire` cobra adapter.
- Non-TTY output has no ANSI when `NO_COLOR=1` or `TERM=dumb` and uses the exact spinner/progress/table fallback shapes above.
- Injected streams let tests capture Output and feed prompt answers without a real TTY.
- Plugin command names without `:` fail registration with a named error.
Both binaries expose namespaced commands and usable output in interactive and CI environments.
Task 3: Rebuild and restart the hello binary during source edits
internal/dev/watch.go, internal/dev/watch_test.go, internal/build/build.go, cmd/summer/main.go, go.mod, go.sum
internal/build/build.go, internal/dev/watch.go, internal/dev/watch_test.go, cmd/summer/main.go, go.mod, go.sum, examples/hello/summer.yaml, .planning/phases/01-framework-kernel-foundation/01-CONTEXT.md, .planning/phases/01-framework-kernel-foundation/01-RESEARCH.md
Implement `summer dev` with `github.com/fsnotify/fsnotify` v1.10.1 (D-16). Watch app workspace directories recursively by walking them and adding new directories on Create; include `.go`, `.yaml`, `.yml`, `.env`, `go.mod`, `go.work` and plugin manifests. Ignore `.git`, `bin`, temp build outputs and generated app files to prevent loops. Debounce bursts (for example 200ms) and serialize builds. Call the exact `internal/build` function used by `summer build`; after success stop and reap the old child, start the new app binary with inherited streams, and print `rebuild: ` measured from build start to completion. On build failure keep the old process running and print the build error; on context cancellation stop/reap the child and close the watcher. Do not execute manifest-derived shell commands. Add a smoke test with a temporary workspace to assert one restart after a source edit, no restart after ignored generated output and a latency line.
go test ./internal/dev ./internal/build ./cmd/summer && (cd examples/hello && go test ./...)
- Editing a watched hello plugin `.go` file causes one debounced rebuild and successful restart.
- Build failure leaves the last successful child running; cancellation reaps it.
- A generated `plugins.gen.go` write does not cause an infinite rebuild loop.
- Every rebuild cycle prints measured elapsed time, including the cycle after a single-plugin edit.
The local development loop rebuilds and restarts without an external watcher install.
## Trust Boundaries
| Boundary | Description |
|---|---|
| CLI plugin input → filesystem | Plugin ID and directory values select paths and module names. |
| Filesystem event → build/restart | File changes trigger local tool execution and process replacement. |
| Prompt → terminal | Secret values may be echoed or captured if mode detection is wrong. |
## STRIDE Threat Register
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|---|---|---|---|---|
| T-01-06 | Tampering | `make:plugin` and `plugin:add` paths | mitigate | Validate lowercase vendor.plugin ID and keep generated paths under the app root; reject traversal and duplicate/conflicting entries. |
| T-01-07 | Denial of service | `summer dev` watcher | mitigate | Debounce, ignore output dirs, serialize builds, and reap child processes on cancellation. |
| T-01-08 | Information disclosure | `bonfire` secret prompt | mitigate | Use `term.ReadPassword` for TTY and document plain stdin fallback; never log answers. |
- After each task commit, run `go vet ./... && go test ./...` in root and hello modules.
- Smoke-test `make:plugin`, `plugin:add`, `build` and `dev` against temporary copies of `examples/hello`.
- Capture non-TTY output with pipes; manually inspect one TTY command during phase verification.
- A new plugin is scaffolded, registered and built using only the framework tool.
- CLI output degrades predictably without a TTY.
- A plugin source change triggers a measured rebuild and app restart.