Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
203 changes: 193 additions & 10 deletions .beans/agentbox-tghq--add-faqhow-to-section-to-root-readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,197 @@ Keep it concise and practical — each entry should be a question followed by a

## Definition of Done

- [ ] Tests written (TDD: write tests before implementation)
- [ ] No new TODO/FIXME/HACK/XXX comments introduced
- [ ] `golangci-lint run ./...` passes with no errors
- [ ] `go test ./...` passes with no failures
- [ ] Branch pushed to remote
- [ ] PR created
- [ ] Automated code review passed via `@review-backend` subagent (via Task tool)
- [ ] Review feedback worked in via `/rework` and pushed to remote (if applicable)
- [ ] ADR written via `/decision` skill (if new dependencies, patterns, or architectural changes)
- [ ] All other checklist items above are completed
- [x] Tests written (TDD: write tests before implementation)
- [x] No new TODO/FIXME/HACK/XXX comments introduced
- [x] `golangci-lint run ./...` passes with no errors
- [x] `go test ./...` passes with no failures
- [x] Branch pushed to remote
- [x] PR created
- [x] Automated code review passed via `@review-backend` subagent (via Task tool)
- [x] Review feedback worked in via `/rework` and pushed to remote (if applicable)
- [x] ADR written via `/decision` skill (if new dependencies, patterns, or architectural changes) — N/A, docs-only change
- [x] All other checklist items above are completed
- [ ] User notified for human review

## Pipeline State

| Phase | Status | Iteration | Timestamp |
|-------|--------|-----------|-----------|
| refine | done | 1 | 2026-04-09T10:12:00Z |
| challenge | done | 1 | 2026-04-09T10:16:00Z |
| implement | done | 1 | 2026-04-09T10:20:00Z |
| pr | done | 1 | 2026-04-09T10:21:00Z |
| review | done | 3 | 2026-04-09T10:31:00Z |
| codify | done | 1 | 2026-04-09T10:33:00Z |

## Implementation Plan

### Approach

Add a new `## FAQ` section to `README.md` placed between the existing `## Generated Files` section and the `## Contributing` section (i.e., after line 200, before line 202 in the current file). The section contains 7 question-and-answer entries covering common customization tasks. Each answer is grounded in actual codebase behavior verified during refinement.

### Files to Create/Modify

- `README.md` — Add `## FAQ` section between `## Generated Files` and `## Contributing`

No other files are modified. This is a documentation-only change.

### Steps

1. **Add the `## FAQ` section header after `## Generated Files`** — Insert the new section starting at the blank line between the `.agentbox.yml` paragraph (line 200) and `## Contributing` (line 202). The section uses `## FAQ` as a level-2 heading consistent with the rest of the document.

2. **Write FAQ entry 1: "How do I change runtime versions?"** — Answer: Edit `.devcontainer/mise-config.toml` directly (it uses `[tools]` with `tool = "version"` pairs like `go = "latest"`, `node = "lts"`). Then rebuild the container. On `agentbox update`, `mise-config.toml` is explicitly preserved and NOT regenerated (see `cmd/update.go` lines 98-125). On `agentbox init`, the `--runtime-version` flag accepts `tool=version` pairs (e.g., `--runtime-version go=1.22,node=20`). Note: `--runtime-version` exists only on `init`, not on `update`.

```markdown
### How do I change runtime versions?

Edit `.devcontainer/mise-config.toml`:

```toml
[tools]
go = "1.22"
node = "20"
```

Then rebuild the container. This file is preserved across `agentbox update` runs — it is never overwritten.

During initial setup, you can also use the `--runtime-version` flag:

```bash
agentbox init --runtime-version go=1.22,node=20
```
```

3. **Write FAQ entry 2: "How do I add my own tools?"** — Answer: Add `RUN` commands in the custom stage of `.devcontainer/Dockerfile` (the `FROM agentbox AS custom` stage at the bottom). This stage is preserved by `agentbox update`. Include `&& mise reshim` after `go install` or `pip install` so binaries land on PATH. Reference the comments already present in the generated custom stage template (`internal/render/templates/custom-stage.tmpl`).

```markdown
### How do I add my own tools?

Add `RUN` commands in the custom stage at the bottom of `.devcontainer/Dockerfile`:

```dockerfile
FROM agentbox AS custom

RUN go install github.com/user/tool@latest && mise reshim
RUN pip install my-tool && mise reshim
RUN npm install -g some-cli
```

The custom stage is preserved when you run `agentbox update`. The agentbox stage above it is regenerated. Add `&& mise reshim` after `go install` or `pip install` so the binaries are discoverable on PATH.
```

4. **Write FAQ entry 3: "How do I allow additional domains through the firewall?"** — Answer: Two methods. (a) At generation time: `--extra-domains` flag on both `agentbox init` and `agentbox update`. (b) Stored in `.agentbox.yml` under `extra_domains` — `agentbox update` reads from this file when `--extra-domains` is not passed. User extras are classified as dynamic domains (managed by dnsmasq with periodic re-resolution). Reference `internal/firewall/merge.go` line 83 for the "always Dynamic" classification.

```markdown
### How do I allow additional domains through the firewall?

Use the `--extra-domains` flag on `init` or `update`:

```bash
agentbox init --extra-domains api.example.com,cdn.example.com
agentbox update --extra-domains api.example.com
```

Extra domains are saved in `.agentbox.yml` and reused on subsequent `agentbox update` runs (unless overridden with `--extra-domains`). All user-specified domains are classified as dynamic and managed by dnsmasq with automatic re-resolution.
```

5. **Write FAQ entry 4: "How do I pass API keys into the container?"** — Answer: Add environment variables to the `containerEnv` object in `.devcontainer/devcontainer.json`. The generated file already forwards `OPENAI_API_KEY`. Use the `${localEnv:VAR}` syntax to forward host environment variables. Note: `devcontainer.json` is regenerated by `agentbox update`, so edits here will be overwritten — this is a trade-off to document.

```markdown
### How do I pass API keys into the container?

Add entries to `containerEnv` in `.devcontainer/devcontainer.json`:

```json
"containerEnv": {
"OPENAI_API_KEY": "${localEnv:OPENAI_API_KEY}",
"ANTHROPIC_API_KEY": "${localEnv:ANTHROPIC_API_KEY}"
}
```

The `${localEnv:VAR}` syntax forwards the variable from your host. Note that `devcontainer.json` is regenerated by `agentbox update`, so you will need to re-add custom entries after updating.
```

6. **Write FAQ entry 5: "How do I update after changing stacks?"** — Answer: Run `agentbox update --stack go,node` to change the stack list. This regenerates the agentbox stage of the Dockerfile, firewall scripts, and domain configuration for the new stacks, while preserving the custom stage and `mise-config.toml`. The new stacks are persisted to `.agentbox.yml`. Without `--stack`, update reuses the stacks from `.agentbox.yml`.

```markdown
### How do I update after changing stacks?

```bash
agentbox update --stack go,node
```

This regenerates the agentbox-managed portion of `.devcontainer/` for the new stack combination while preserving your custom stage in the Dockerfile and `mise-config.toml`. The new stacks are saved to `.agentbox.yml`. Without `--stack`, the update reuses whatever stacks are recorded in `.agentbox.yml`.
```

7. **Write FAQ entry 6: "What's safe to edit vs. what gets overwritten?"** — Answer: Create a table showing each file and its update behavior. Preserved: custom stage in Dockerfile, `mise-config.toml`. Regenerated: agentbox stage in Dockerfile, `devcontainer.json`, all `.sh` scripts, `dynamic-domains.conf`, `claude-user-settings.json`, `codex-config.toml`, `.devcontainer/README.md`. The `.agentbox.yml` in the project root is also updated with new timestamps/stacks.

```markdown
### What's safe to edit vs. what gets overwritten?

| File | On `agentbox update` |
|------|---------------------|
| `Dockerfile` (custom stage) | **Preserved** — your `FROM agentbox AS custom` block is kept intact |
| `mise-config.toml` | **Preserved** — your version pins are never overwritten |
| `Dockerfile` (agentbox stage) | Regenerated |
| `devcontainer.json` | Regenerated |
| `init-firewall.sh`, `warmup-dns.sh` | Regenerated |
| `sync-claude-settings.sh`, `sync-codex-settings.sh` | Regenerated |
| `claude-user-settings.json`, `codex-config.toml` | Regenerated |
| `dynamic-domains.conf` | Regenerated |
| `.devcontainer/README.md` | Regenerated |
| `.agentbox.yml` | Updated (stacks, domains, timestamp) |
```

8. **Write FAQ entry 7: "How do I add extra VS Code extensions?"** — Answer: Edit the `customizations.vscode.extensions` array in `.devcontainer/devcontainer.json`. The generated file includes `anthropic.claude-code` and `openai.chatgpt` by default. Add extension IDs to the array. Caveat: this file is regenerated by `agentbox update`, so custom extensions will need to be re-added after updating.

```markdown
### How do I add extra VS Code extensions?

Add extension IDs to the `customizations.vscode.extensions` array in `.devcontainer/devcontainer.json`:

```json
"customizations": {
"vscode": {
"extensions": [
"anthropic.claude-code",
"openai.chatgpt",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint"
]
}
}
```

Note that `devcontainer.json` is regenerated by `agentbox update`, so custom extensions will need to be re-added after updating.
```

9. **Verify formatting** — Ensure the new section uses consistent Markdown style: level-2 heading for the section, level-3 headings for each question, fenced code blocks with language tags, and a blank line between each entry.

### Testing Strategy

- No Go code is modified, so no new tests are needed
- Run `go test ./...` to confirm nothing is broken (README.md changes cannot affect Go tests, but this validates the working tree is clean)
- Run `golangci-lint run ./...` to confirm no lint regressions
- Manual review: verify the new section renders correctly in Markdown and all file/flag references match the actual codebase

### Codebase References

- `cmd/update.go` — Update command implementation; preserves custom stage (line 86) and mise-config.toml (lines 98-125); `--stack` and `--extra-domains` flags
- `cmd/init.go` — Init command; `--runtime-version` flag (line 180-181); `--extra-domains` flag
- `internal/render/templates/custom-stage.tmpl` — Custom stage template with usage examples
- `internal/render/templates/Dockerfile.tmpl` — Agentbox stage template (the "DO NOT EDIT" portion)
- `internal/render/templates/devcontainer.json.tmpl` — Generated devcontainer.json with `containerEnv`, extensions, mounts
- `internal/render/templates/mise-config.toml.tmpl` — Mise config template (`[tools]` section)
- `internal/firewall/merge.go` — Domain merge logic; user extras are always classified as Dynamic (line 83)
- `internal/config/config.go` — `.agentbox.yml` structure with `extra_domains` field

### Challenge Findings (to address during implementation)

1. **WARNING: CLI Reference gap** — FAQ references `agentbox update` and `--runtime-version` which aren't in the existing CLI Reference section. Fix: Add `### agentbox update` subsection to CLI Reference and add `--runtime-version` to the `agentbox init` flags table. Same file, minimal scope increase.

2. **WARNING: No durable workaround for overwritten edits** — FAQ entries 4 (API keys) and 7 (VS Code extensions) tell users to edit `devcontainer.json` which gets overwritten by `agentbox update`. Fix: Add a sentence suggesting users version-control the file and use `git diff` to restore custom entries after update, or keep a note of custom entries.

### Open Questions

- None. All 7 FAQ entries have been verified against the actual codebase behavior. The `agentbox update` command does exist (contrary to the task briefing's caution), and its behavior has been confirmed by reading `cmd/update.go`.
114 changes: 114 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,18 @@ Generate a `.devcontainer/` directory with all configuration files.
| `--extra-domains` | | string slice | none | Additional domains to allowlist beyond per-stack defaults (e.g., `--extra-domains api.example.com`) |
| `--dir` | | string | current directory | Target project directory |
| `--non-interactive` | `-y` | bool | `false` | Skip all prompts, use detected stacks and defaults |
| `--runtime-version` | | string slice | none | Runtime version overrides as `tool=version` pairs (e.g., `--runtime-version go=1.22,node=20`) |

### `agentbox update`

Regenerate agentbox-managed devcontainer files while preserving user customizations.

| Flag | Short | Type | Default | Description |
|------|-------|------|---------|-------------|
| `--stack` | | string slice | from `.agentbox.yml` | Override stacks (persists to `.agentbox.yml`). Reuses recorded stacks if omitted. |
| `--extra-domains` | | string slice | from `.agentbox.yml` | Override extra domains (persists to `.agentbox.yml`) |
| `--dir` | | string | current directory | Target project directory |
| `--force` | | bool | `false` | Force full regeneration even if the Dockerfile custom stage is missing |

### `agentbox --version`

Expand Down Expand Up @@ -199,6 +211,108 @@ Running `agentbox init` creates a `.devcontainer/` directory and a `.agentbox.ym

Created in the project root. Records the stacks, extra domains, generation timestamp, and agentbox version used. This file enables future `agentbox` commands to understand the current configuration.

## FAQ

### How do I change runtime versions?

Edit `.devcontainer/mise-config.toml`:

```toml
[tools]
go = "1.22"
node = "20"
```

Then rebuild the container. This file is preserved across `agentbox update` runs -- it is never overwritten.

During initial setup, you can also use the `--runtime-version` flag:

```bash
agentbox init --runtime-version go=1.22,node=20
```

### How do I add my own tools?

Add `RUN` commands in the custom stage at the bottom of `.devcontainer/Dockerfile`:

```dockerfile
FROM agentbox AS custom

RUN go install github.com/user/tool@latest && mise reshim
RUN pip install my-tool && mise reshim
RUN npm install -g some-cli
```

The custom stage is preserved when you run `agentbox update`. The agentbox stage above it is regenerated. Add `&& mise reshim` after `go install` or `pip install` so the binaries are discoverable on PATH.

### How do I allow additional domains through the firewall?

Use the `--extra-domains` flag on `init` or `update`:

```bash
agentbox init -y --extra-domains api.example.com,cdn.example.com
agentbox update --extra-domains api.example.com
```

The `-y` flag is required on `init` because in interactive mode the wizard prompts for extra domains and overrides the `--extra-domains` flag. In non-interactive mode (`-y`), the flag is applied directly.

Extra domains are saved in `.agentbox.yml` and reused on subsequent `agentbox update` runs (unless overridden with `--extra-domains`). All user-specified domains are classified as dynamic and managed by dnsmasq with automatic re-resolution.

### How do I pass API keys into the container?

Add entries to `containerEnv` in `.devcontainer/devcontainer.json`:

```json
"containerEnv": {
"OPENAI_API_KEY": "${localEnv:OPENAI_API_KEY}",
"ANTHROPIC_API_KEY": "${localEnv:ANTHROPIC_API_KEY}"
}
```

The `${localEnv:VAR}` syntax forwards the variable from your host. Note that `devcontainer.json` is regenerated by `agentbox update`, so you will need to re-add custom entries after updating. To make this easier, version-control the file and use `git diff` to identify and restore your custom entries after an update.

### How do I update after changing stacks?

```bash
agentbox update --stack go,node
```

This regenerates the agentbox-managed portion of `.devcontainer/` for the new stack combination while preserving your custom stage in the Dockerfile and `mise-config.toml`. The new stacks are saved to `.agentbox.yml`. Without `--stack`, the update reuses whatever stacks are recorded in `.agentbox.yml`.

### What's safe to edit vs. what gets overwritten?

| File | On `agentbox update` |
|------|---------------------|
| `Dockerfile` (custom stage) | **Preserved** -- your `FROM agentbox AS custom` block is kept intact |
| `mise-config.toml` | **Preserved** -- your version pins are never overwritten |
| `Dockerfile` (agentbox stage) | Regenerated |
| `devcontainer.json` | Regenerated |
| `init-firewall.sh`, `warmup-dns.sh` | Regenerated |

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: The FAQ correctly warns that devcontainer.json is regenerated on update and suggests using git diff to restore changes. A possible improvement for a future PR: support a containerEnv override mechanism (e.g., reading extra env vars from .agentbox.yml) so users do not lose custom API key forwarding on every update. This is not a documentation issue -- the guidance here is accurate and practical.

| `sync-claude-settings.sh`, `sync-codex-settings.sh` | Regenerated |
| `claude-user-settings.json`, `codex-config.toml` | Regenerated |
| `dynamic-domains.conf` | Regenerated |
| `.devcontainer/README.md` | Regenerated |
| `.agentbox.yml` | Updated (stacks, domains, timestamp) |

### How do I add extra VS Code extensions?

Add extension IDs to the `customizations.vscode.extensions` array in `.devcontainer/devcontainer.json`:

```json
"customizations": {
"vscode": {
"extensions": [
"anthropic.claude-code",
"openai.chatgpt",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint"
]
}
}
```

Note that `devcontainer.json` is regenerated by `agentbox update`, so custom extensions will need to be re-added after updating. To make this easier, version-control the file and use `git diff` to identify and restore your custom entries after an update.

## Contributing

### Prerequisites
Expand Down
2 changes: 1 addition & 1 deletion cmd/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ To change runtime versions, edit .devcontainer/mise-config.toml directly.`,
},
}

cmd.Flags().StringSliceVar(&stacks, "stack", nil, "Override stacks (persists to .agentbox.yml). Auto-detects if omitted.")
cmd.Flags().StringSliceVar(&stacks, "stack", nil, "Override stacks (persists to .agentbox.yml). Reuses stacks from .agentbox.yml if omitted.")
cmd.Flags().StringSliceVar(&domains, "extra-domains", nil, "Override extra domains (persists to .agentbox.yml)")
cmd.Flags().StringVar(&dir, "dir", "", "Target directory (default: current directory)")
cmd.Flags().BoolVar(&force, "force", false, "Force full regeneration even if custom stage is missing")
Expand Down