# CodeHero Developer Training — The Autonomous Development Framework (ADF)

**Version 1.0 · September 2026 · For CodeHero PRO 4.48 and later**

This is the training course for developers who will design, configure and operate CodeHero projects. It teaches the *Autonomous Development Framework* (ADF): the method CodeHero implements, in which AI agents build, test and document a product from a specification while humans provide only what nobody else can — the business truth, the credentials, and the approvals.

The course is written in English so it can be shared with any team. Trainees may speak Greek or English with the platform; CodeHero replies in the user's language.

---

## How to use this course

**Who it is for.** Developers, analysts and technical project managers who will:

1. extract requirements from a client and turn them into a specification package;
2. plan a CodeHero project (tickets, roles, providers, execution settings);
3. operate the run (read reports, answer questions, unblock tickets, verify results);
4. adapt the framework itself by editing the global context and the project contexts.

**Prerequisites.** Basic web development knowledge (HTTP, HTML, a backend language, SQL). A working CodeHero PRO installation with at least two active AI providers (one vision-capable). Read the User Guide chapters 2, 6, 8, 9, 11, 13, 14 and 15 first — this course assumes you know the UI.

**Structure.** Eight modules, in the order the work happens in real life. Each module ends with **Exercises**; Module 8 is a capstone with a grading rubric. Suggested pace: one module per half-day, capstone on day five.

| Module | Title | You will be able to |
|---|---|---|
| 1 | The framework | Explain the ADF principles and the CodeHero pipeline |
| 2 | Extracting knowledge from the client | Run a Spec Builder interview and produce a specification package |
| 3 | Choosing the stack | Decide PHP vs Node vs Python vs .NET, host vs container, with a written reason |
| 4 | Planning | Turn a package into a serial ticket plan with roles, providers and verification |
| 5 | Execution | Read what the agent does, why it stops, and how to answer it |
| 6 | Customizing the brain | Change global and project contexts safely, and prove the change works |
| 7 | Reaching a working result | Drive a project from first ticket to a verified, documented delivery |
| 8 | Capstone | Do all of the above on a real mini-project and pass the rubric |

**Files this course refers to.** All paths are relative to the CodeHero source tree (`/home/claude/codehero/` on a development machine) or the installed tree (`/opt/codehero/` and `/etc/codehero/` on a server).

| File | What it is |
|---|---|
| `config/global-context.md` | The global context v6.1 **core**: the rules every agent gets on every ticket |
| `config/guides/*.md` | The ten **on-demand guides** of the global context (planning, verify-fix, asking, helper, debugging, frontend, database, build, testing, native): the agent opens one with `codehero_get_guide` when its trigger fires; the daemon pre-loads the guide of a ticket's kind (`[PLAN]`, `[REPLAN]`, `[VERIFY]`, `[FIX]`, `[HELPER]`, `[PEER]`) |
| `config/contexts/<stack>.md` | Per-language project contexts (php, node, python, html, react, dotnet, go, java, kotlin, swift, flutter, capacitor, presentation, reporting, api, hybrid) |
| `docs/CODEHERO_PLANNING_GUIDE.md` | The Spec Builder knowledge file (v1.9): how to interview a client and produce a specification package |
| `config/assistant-planner.md` | The in-app "Plan with AI" planner: how a specification (written with the user or imported) becomes a project plus ONE planning ticket |
| `config/assistant-general.md`, `assistant-progress.md`, `assistant-help.md` | The other in-app assistant modes |
| `docs/USER_GUIDE.md` | The user manual (UI reference) |

Keep these files open while you study. The course explains them; it does not replace them.

**Presentations.** The website carries slide decks with speaker notes at [presentations/](presentations/index.html). The first one, [*The Domain Expert's Software Factory*](presentations/domain-experts.html), tells the story of this course to business people with no technical background (interview → approval → build and verification → handoff, with the RepairFlow example of Modules 2–7). Use it to open a client workshop or to brief the domain experts you will interview; the developer material stays here.

---

# PART I — FOUNDATIONS

## Module 1 — The framework: what ADF is and how CodeHero implements it

### 1.1 The one-sentence definition

> An autonomous development framework is a set of rules, roles and checkpoints that lets AI agents deliver working software **without a human in the build loop**, while guaranteeing that every business decision comes from a human, every claim of success comes with evidence, and every failure is visible.

CodeHero is a complete implementation of that idea: a platform (web UI, daemon, agent, tools, database, containers) plus a written method (the global context, the Spec Builder guide, the planner). This course teaches the method; the User Guide teaches the platform.

### 1.2 Why a framework at all

Give a strong model a task and it will write code. That is not the problem. The problems appear in the second hour:

- it **guesses a business rule** (a discount, a permission, a deadline) and builds the wrong product with confidence;
- it **claims success** ("this should work now") without loading the page;
- it **loses its memory** when the context window fills, and repeats or contradicts earlier work;
- it **breaks something that worked** while fixing something else;
- it **weakens a protection** (turns off validation, hand-inserts a row) to make a test pass;
- two agents working at once **edit the same file** and corrupt each other's work.

Every rule in ADF exists because one of these happened in a real run. The framework is not theory; it is the accumulated set of guardrails from production deliveries. When you later customize the contexts (Module 6), remember that: change a rule only when you know which failure it prevents.

### 1.3 The twelve principles

These are the principles behind the global context (`config/global-context.md`). Learn them by name; the rest of the course refers back to them.

| # | Principle | In one line | Where it lives |
|---|---|---|---|
| P1 | **The agent is the only engineer** | Nobody helps during the build. The agent understands, plans, builds, tests, documents. | Global §0 |
| P2 | **Evidence, not claims** | "Done" means a test ran, a page loaded, a row exists, a screenshot was taken. Text saying it works is not done. | Global §0 rule 2, §3, §9 |
| P3 | **Never guess a business rule** | Technical choices are the agent's job; business rules (money, permissions, workflows, statuses, edge cases) come only from the client. | Global §4 |
| P4 | **AI before human** | Before a question reaches the client, a second AI on another provider tries to find the answer in the material. Only what is genuinely business-only goes to the human. | Global §4.1, `guides/asking.md`, `guides/helper.md` |
| P5 | **Safe defaults, and BLOCKED is never PASS** | When no answer can come, pick the option that cannot hurt anyone (deny access, keep history, notify, fail closed) and record it. Missing credentials make a part BLOCKED, never "done". | Global §4.1, `guides/asking.md` |
| P6 | **Memory on disk** | Context compaction is assumed. Anything not written to the SPEC FILE or the KNOWLEDGE BASE is treated as if it never happened. | Global §6, §7 |
| P7 | **Serial by default** | One ticket at a time, each with its own `sequence_order`. Parallel only after the user says yes and a file-ownership analysis proves zero shared files. | Global H6, `guides/planning.md` §2 |
| P8 | **Core slice first** | The first milestone is the thinnest end-to-end slice of what the product is for, proven on the preview URL, before any secondary feature. | `guides/planning.md` step 6 (value order) |
| P9 | **Verify without building** | A VERIFY ticket on a different provider only checks; findings become one fix ticket for the original builder; a circuit breaker stops endless loops. | `guides/verify-fix.md` |
| P10 | **Never invent facts** | No invented config keys, model names, API abilities, credentials or test results. Unknown → probe it, read the real docs, or mark it BLOCKED. | Global H8 |
| P11 | **Root cause, never symptom; never weaken protection** | Debugging follows a fixed protocol; the WAF, auth, CSRF and validation stay on; a regression jumps the queue. | Global H3, §8 |
| P12 | **Self-contained tickets on a "normal server"** | Every ticket text carries objective, owned files, contracts, environment facts (`localhost` only) and a definition of done. The agent never hears the word "container". | Planner rules 6–8, Planning Guide §7.1 |

A useful mental test when you evaluate a plan, a context change or a ticket: *which principle does this serve, and which one does it risk?*

### 1.4 The pipeline: from client conversation to verified software

```
 CLIENT (domain expert)
      │  interview, one question at a time, four statuses
      ▼
 SPEC BUILDER  (claude.ai / ChatGPT project + CODEHERO_PLANNING_GUIDE.md)
      │  specification package: header + codehero_environment + run settings
      │  + registers (requirements, decisions, dependencies) + ticket plan
      ▼
 PLAN WITH AI  (in-app planner, config/assistant-planner.md)
      │  writes the specification with the user or imports the package,
      │  shows preview → operator confirms → creates project + ONE [PLAN] ticket
      ▼
 PLANNING TICKET  ([PLAN] … in PLAN MODE, guides/planning.md, on the real installation)
      │  baseline → requirements → contracts → dry run → review rounds → peer check
      │  → assigns providers → creates the FIRST PHASE of tickets (last one: [REPLAN])
      ▼

 DAEMON + AGENT  (codehero-daemon → HeroAgent or CLI provider, per ticket)
      │  global context + project context + ticket → build → verify → report
      │  SPEC FILES (.specs/) + KNOWLEDGE BASE (graph) + git snapshots
      ▼
 VERIFY / FIX / REPLAN tickets  (different provider, master + ultra)
      │
      ▼
 HANDOFF REPORT → operator → client   (works+evidence · waiting on you · decided for you · open)
```

Three "brains" take part, and it matters which one you are talking to:

| Brain | Where | Knowledge it reads | Its job |
|---|---|---|---|
| **Spec Builder** | Outside CodeHero: a claude.ai or ChatGPT project with the Planning Guide uploaded as knowledge | `docs/CODEHERO_PLANNING_GUIDE.md` | Interview the client, decide all technical matters, run 50 review rounds, output the package. Names roles and think modes, never providers. |
| **In-app planner** | CodeHero → AI Assistant → *Plan with AI* | `config/assistant-planner.md` + the global context | Write the specification with the user (or import the package), settle everything only a person can decide, show a preview, and after the operator confirms create the project, its environment and ONE planning ticket. It designs no tickets itself. |
| **Executing agent** | Spawned by the daemon for each ticket (HeroAgent for API providers; Claude Code or Codex CLI for subscription modes) | Global context core + the guide of its kind (auto-loaded) + guides on demand (`codehero_get_guide`) + language context + project context + environment blocks + ticket text + conversation | Build, verify, document, report. A `[PLAN]` ticket plans; a `[VERIFY]` ticket checks and owns the fix loop; a `[REPLAN]` ticket compares the product with the baseline and plans the next phase. |

The Spec Builder is deliberately outside the platform: it needs a long, calm conversation with a business person, file uploads, and no server access. The other two live inside CodeHero because they need the installation's real facts (active providers, ports, containers).

### 1.5 The machinery (enough to reason about it)

You do not need to read the source to operate CodeHero, but you must know what runs where, because every question in Module 5 ("why did it stop?") comes back to one of these parts.

| Part | Service / file | What it does |
|---|---|---|
| Web app | `codehero-web` (Flask + SocketIO; nginx on port 9453) | UI, REST API, live console, terminal, AI Assistant sessions |
| Daemon | `codehero-daemon` (`scripts/claude-daemon.py`) | Picks the next ticket per project, assembles the prompt, spawns the agent, watches it, reviews the outcome, retries, snapshots |
| Agent | HeroAgent (`heroagent/heroagent.py`) or a CLI provider | The tool loop: model call → tool calls → results → repeat until `TASK COMPLETED` |
| MCP server | `scripts/mcp_server.py` | The `codehero_*` tools the agent (and the assistant) call: projects, tickets, knowledge graph, git snapshots, containers, screenshots, context extraction |
| Permission hook | `scripts/permission_hook.py` | The single choke point every tool call passes through: execution-mode policy, path protection, container routing, loop detection |
| Database | MySQL `claude_knowledge` (`database/schema.sql`) | `projects`, `tickets`, `ticket_dependencies`, `conversation_messages`, `conversation_extractions`, `knowledge_nodes`, `knowledge_edges`, `project_services`, … |
| Preview proxy | nginx on port 9867 | Serves every project at `https://127.0.0.1:9867/<project-folder>/` — the only URL the agent may test on |
| Containers | LXC + BTRFS (`heroagent/container_manager.py`) | Optional per-project isolation with provisioned services; the agent's commands are routed inside transparently |

Ports 9453 and 9867 are the defaults; the real values come from `/etc/codehero/system.conf` (`ADMIN_PORT`, `PROJECTS_PORT`) and are substituted into the context as `{ADMIN_PORT}` and `{PROJECTS_PORT}`.

### 1.6 The layers of instruction

When a ticket runs, the agent's system prompt is assembled from layers, in this order (see `build_project_context_file()` in the daemon):

1. `=== CURRENT WORKING PROJECT ===` — project id, name, ticket id; the isolation stamp ("pass `project_id=<id>` to every `codehero_*` tool").
2. A **knowledge-graph snapshot** — the most relevant nodes of the project's knowledge base.
3. `=== PROJECT GLOBAL CONTEXT ===` — the project's stored copy of the global context, placeholders resolved.
4. `=== PROJECT CONTEXT ===` — the project's stored copy of the language/stack context.
5. `=== PROJECT DESCRIPTION ===` and `=== PROJECT INFO ===` — the description and the free "additional notes" field of the project.
6. `=== RUNTIME ENVIRONMENT ===` — pinned runtime versions ("already installed — do NOT reinstall").
7. `=== SERVER PORTS ===` — the concrete preview URL.
8. `=== PROJECT SERVICES ===` — databases, caches and web apps with `localhost:<port>` and credentials ("already installed and running").
9. Container execution rules and the container app-deployment guide (container projects only).
10. Smart-context material — project map, prior extraction summaries, recent history.

Then the user-turn prompt adds: project paths, the database block, the ticket's own context, the parent ticket chain, the ticket title and description, the allowed write paths, and the completion contract ("end your final message with `TASK COMPLETED: <summary>`").

Two consequences you will use constantly:

- **Precedence is by specificity.** The global context sets the method; the language context sets the stack idioms and must defer to the global for shared rules; the project context and the ticket carry the facts of this project. A ticket description can add facts; it should never contradict the method.
- **Contexts are copied per project at creation.** Editing `config/global-context.md` changes *new* projects. An existing project keeps its stored copy until you edit it in *Project Settings → Context* or load the defaults again (Module 6).

### 1.7 Glossary you must know before Module 2

| Term | Meaning |
|---|---|
| **Ticket** | One task. Has a title, a description, `sequence_order`, optional `depends_on`, optional parent, a role (`ai_model`), a provider, a think mode, an execution mode. |
| **Role** | `master_developer`, `senior_developer`, `junior_developer`. Tickets store a *role*, not a model id; each provider maps roles to concrete models in `heroagent/heroagent.conf` (`model_aliases`). |
| **Think mode** | `off` / `basic` / `balanced` / `ultra` — extended-thinking budget. `ultra` is reserved for planning, replan, verification, peer review, helpers and explicit user choice. |
| **Provider** | anthropic, openai, gemini, grok, deepseek, glm, openrouter, ollama, vllm (plus generic OpenAI-compatible slots). Only *active* providers (valid credentials) may be planned. |
| **Execution mode** | `autonomous` (no prompts), `semi-autonomous` (auto-approves safe operations, asks for risky ones, blocks dangerous ones), `supervised` (asks before every write/edit/command). |
| **Relaxed / strict** | `deps_include_awaiting = 1` / `0`. Relaxed: the auto-reviewer may close a finished ticket. Strict: a human closes it. |
| **SPEC FILE** | `.specs/<NNN>-<task>.md` inside the project: the agent's plan and live progress log for one task. |
| **KNOWLEDGE BASE** | The project's knowledge graph (`codehero_knowledge_search` / `codehero_knowledge_store`): decisions, failed approaches, components, endpoints, patterns. |
| **SNAPSHOT** | A git backup taken by `codehero_git_operations` (`backup_snapshot`); automatic at ticket start and after each verified part. |
| **PREVIEW URL** | `https://127.0.0.1:{PROJECTS_PORT}/{PROJECT_FOLDER}/` — the only place the agent may test a web page. |
| **VERIFY ticket** | A ticket that only checks another ticket's work. Different provider, `master_developer`, `ultra`. Never edits code. |
| **HELPER ticket** | A parallel ticket on another provider that only advises by messages. Opened and closed by the ticket that needs it. |
| **Walkie-talkie** | Ticket-to-ticket messaging: `codehero_update_ticket(ticket_id=<other numeric id>, reply=...)`. The platform signs a reply from a ticket (`📨 FROM TICKET #id`); a working ticket receives it at its next step, a parked one (`⏸ WAITING-FOR-TICKET #id`, several ids allowed) is woken by it, and a ticket that ends its turn with a message still unread is re-opened at once. |
| **TASK COMPLETED** | The completion marker. The agent may say it only when the work is finished *and* the output was checked. |

### Exercises — Module 1

1. Open `config/global-context.md`. For each of the twelve principles, find the exact section and copy one sentence that states it. (You will need these citations in Module 6.)
2. Read the glossary table in §0 of the global context. Explain in your own words the difference between the SPEC FILE and the KNOWLEDGE BASE, and why the framework keeps both.
3. On your training installation, open *Settings* and list the active providers. Mark which ones have vision. Keep this list; every plan in Modules 4 and 8 must respect it.
4. In the daemon's log (`journalctl -u codehero-daemon -f`) watch one ticket run from start to finish. Write down the sequence of statuses you observed.

---
# PART II — EXTRACTING KNOWLEDGE FROM THE CLIENT

## Module 2 — The Spec Builder interview and the specification package

### 2.1 The problem this module solves

The most expensive mistakes in software are made before the first line of code: a misunderstood process, an unstated rule, a wish mistaken for a capability. In ADF the build is autonomous, so there is no developer in the loop to notice a misunderstanding half-way. Everything the agents will need must be extracted from the client *before* the run, in a form the agents can use.

The Spec Builder does that. It is not a form; it is an interviewer with a method, and the developer's job is to run it well, review its output critically, and know when it is done.

### 2.2 Setting it up

1. Create a project in claude.ai (or a ChatGPT project). Upload `docs/CODEHERO_PLANNING_GUIDE.md` as project knowledge.
2. Set the project instruction to exactly: *"You are the CodeHero Spec Builder. Follow the file `CODEHERO_PLANNING_GUIDE.md` exactly."*
3. Start the conversation with the client's material (spreadsheets, screenshots, the current manual) already uploaded, so the assistant reads them before asking anything.

Who sits at the keyboard? Two working arrangements are common:

- **The client types.** The Spec Builder was written for a domain expert with no technical background: one question per message, no jargon, a proposed answer whenever it has a basis for one. You review the transcript and the package afterwards.
- **You type, with the client next to you (or on a call).** Faster for small tools; you can rephrase the assistant's question in the client's own words and keep it on track. You must resist the temptation to answer business questions yourself.

Either way, **the developer never invents a business fact**. That rule binds you exactly as it binds the agents (P3, P10).

### 2.3 The four statuses — the backbone of the whole method

Every requirement and every decision in the package carries one status and one origin:

| Status | Meaning | Who resolves it |
|---|---|---|
| **Confirmed** | The client said it, or a source document shows it | — |
| **Assumed** | A reasonable business assumption that still needs confirmation | The client, at the preview or the final confirmation |
| **Technical** | The Spec Builder's own choice, with a reason; never asked of the client | The developer may override with a recorded reason |
| **Open** | A missing element that affects the build | Must be closed before the package is *Ready to build* — unless the client agrees to move it to *Later* |

Origin is `user`, `document` or `agent`. A requirement the assistant proposed and the client approved is *Confirmed / agent*. The origin column is what lets the client later audit "what did I ask for, and what did you add?".

Two rules make the statuses honest:

- **"I don't know" is an answer.** A technical gap is filled silently as *Technical*. A business gap becomes *Assumed*, with one sentence saying what was assumed.
- **Critical items are never silently assumed.** Anything that decides money, approvals, deletion rights, legal or compliance obligations, or safety stays **Open** and visible in every summary until the client confirms it — even when the client wants to finish quickly.

You will see the same distinction again at run time: the agent's SAFE DEFAULT (P5) is exactly an *Assumed* item chosen so that it cannot hurt anyone, and CRITICAL questions stop the ticket instead of getting a default.

### 2.4 The interview, stage by stage

Part 2 of the Planning Guide is a **coverage checklist**, not a script. The assistant asks in the order the conversation makes natural, skips what a document already answers, and adapts wording to the industry. As the developer, you check coverage at the end: did every stage get answered or consciously defaulted?

| Stage | What must be known afterwards | Typical count |
|---|---|---|
| 0 Setup | What to organize, existing documents, a name, who will maintain it | 2–3 |
| 1 Company and purpose | The business, the pain, who suffers, success in six months, internal vs external users, countries, what must *never* happen | 5–7 |
| 2 The work itself | The "things" tracked, their fields, what keeps history, the steps of the main process, who does each, rules and calculations, exceptions, documents in and out, other systems, volumes, late/duplicate data | 10–15 |
| 3 People and rights | User types, what each sees and changes, who may delete/approve/export (critical), scoping by branch/team, admin area, concurrency, external logins, audit | 6–10 |
| 4 Notifications, reports, integrations | When someone must be told, channels people actually read, reports, exports, scheduled emails, automatic data exchange | 5–8 |
| **C Constraints** (mandatory before any architecture) | Integrations and whether they are occasional or continuous; offline or background operation; time limits and continuous data; existing hosting, devices and support; initial and monthly budget | 5 |
| **P Preview** (mandatory) | The main screen as a text wireframe, the main process walked through with the client's own example, each role in one line, the status summary. Then: *"Is this how you work? Tell me what is wrong."* | 1 loop |
| 5 Speed, scale, real time, mobile | How fast others must see a change, alarms where seconds matter, sensors, where it is used, offline, store app vs website, camera/GPS/push, growth | 6–9 |
| 6 Look, feel and brand | Logo and colors, feel, references, theme, languages, units, accessibility | 5–8 |
| 7 Security, compliance, hosting | Personal data, 2FA, session length, security testing, where it runs, domain and SMTP, audit proof, backup tolerance, confirmed monthly cost | 6–9 |
| 8 Priorities and go-live | The one part that must be ready first, the MVP/Optional/Later split, data import, first administrator, training, deadline, "anything you were afraid to ask?" | 5–7 |

Note the two mandatory checkpoints. **Stage C** comes before any technology decision, because the constraints — not the archetype — decide the stack (Module 3). **Stage P** comes before scale, brand and security, because a misunderstanding caught at the preview costs one message and the same misunderstanding caught after the build costs dozens of tickets.

### 2.5 A worked interview: "RepairFlow"

We will follow one example through the whole course. A small electronics repair company with three technicians tracks repair jobs in an Excel sheet. Jobs get lost, deadlines are missed, and the owner cannot see who is doing what.

The opening question is always the same: *"Which piece of your work do you want to organize or automate? Describe a real example — what happened last time, step by step."*

Extracts from the transcript, with the status the Spec Builder assigned:

| Client said | Became | Status / origin |
|---|---|---|
| "A customer brings a laptop, we write it in the sheet with a number, a technician takes it, when it's fixed we call the customer, they pay and pick it up." | Entity *Job* with states `received → in_repair → ready → delivered`; entities *Customer*, *Technician* | Confirmed / user |
| Column H in the sheet is `=D2+14` | Business rule: *deadline = received date + 14 days* | Confirmed / document (the assistant restated it and the client said yes) |
| "Red cells are the ones we are late on." | Rule: a job past its deadline and not `ready` is *overdue*; overdue jobs are highlighted and the manager is notified daily | Confirmed / user (highlight) + Assumed / agent (daily email) |
| "Only I give discounts." | Permission: discount requires the *Owner* role | **Open — critical** until the client confirmed the exact roles who may discount and the maximum |
| "We'd like customers to check the status themselves one day." | Customer portal | Later |
| "Sometimes two technicians work on the same job." | Job has one *responsible* technician and optional *helpers*; history keeps who did what | Assumed / agent, confirmed at preview |
| "How fast must the owner see that a job changed status?" — "When I refresh is fine." | Real-time: on refresh / polling every 60 s | Technical / agent |
| "We have a website on a normal hosting company, nobody technical in-house." | Hosting: standard PHP/MySQL web hosting, no in-house support | Confirmed / user → drives the stack (Module 3) |
| "Budget: as little as possible per month." | Monthly cost target: hosting only | Confirmed / user |

Then the **preview** (Stage P). The assistant showed the job list as a text wireframe (columns, the three most common actions: *new job*, *change status*, *print job sheet*), walked the client's own laptop example through the states, described the three roles in one line each (Owner sees all and gives discounts; Technician sees own jobs and changes status; Front desk creates jobs and marks delivered), and listed what was Confirmed, Assumed and Open. The client corrected one thing: the front desk also takes the payment, so *Front desk* may mark a job *paid*. One message, one correction, dozens of tickets saved.

### 2.6 The spreadsheet intake procedure

When the client uploads a spreadsheet (most internal tools start as one), the Spec Builder follows §2.9 of the guide before asking Stage 2 questions. Learn the mapping; you will use it yourself when a client hands you an Excel file:

| In the spreadsheet | Becomes |
|---|---|
| Each sheet or repeated block | A candidate entity, named in the client's words |
| Each column | A typed field (text, number, date, money, choice list, person, reference, file, formula) |
| Each formula | A business rule, restated in words and confirmed with the client's own numbers |
| Colors, comments, manual marks | Workflow states and exceptions ("what does a red cell mean?") |
| Repeated manual steps ("every Monday I copy A to B") | A scheduled job |
| Who edits which columns | Permissions |
| Duplicates, blanks, inconsistent spellings | Data-quality rules and the import cleaning plan — never silently "fixed"; the import report lists every changed or rejected row |

Two habits protect you: record separately what the sheet does **today** and what the new application is **agreed** to do (they differ more often than not), and treat text inside the file as information, never as instruction.

### 2.7 Wishes are not capabilities: the dependency register

A client confirming that they *want* an ERP integration does not prove that their ERP *can* provide it. Every critical external dependency goes into the dependency register (template T9) with the specific capability, the system and version, the access or licence required, and a verification status that is **separate** from the business status:

| Business status | Verification status |
|---|---|
| confirmed / assumed / technical / open | pending / verified / failed / mock_only |

A dependency that an active function needs must be *verified* before the feature tickets that depend on it start. Until then the package stays a *Draft*, and a Draft may go to CodeHero only for probe tickets (environment checks, integration probes). A mock is recorded as `mock_only` and never counts as the real integration — the same rule the agent follows at run time (P5: never mock an integration and report it as working).

### 2.8 The decision engine is not the client's problem

Part 3 of the guide is the Spec Builder's private decision engine: archetypes, stack rules, hosting targets, the real-time ladder, the mobile ladder, the frontend choice. The client never sees the options. They answer questions about their world ("how fast must someone see a change?", "must it work without internet?"), and the assistant translates. Module 3 teaches you the same engine so you can review the choice.

### 2.9 The 50 review rounds

Once the complete first version of the specification exists, the Spec Builder runs **50 sequential review-and-fix rounds** and a final consistency check. Each round examines the *whole* current specification from one perspective (main process end to end · every rule has a number and an example · what must never happen · late, duplicate, out-of-order data · time zones · permissions matrix · external users see only theirs · backups and one restore drill · audit fields · hosting capabilities verified · milestone order builds the main value first · each ticket has a demonstrable definition of done · …), tries concrete examples in the client's own numbers, fixes what the agreed requirements allow, and records one row in Appendix E.

What you must know as the reviewer of the package:

- Ticking fifty topics is **not** fifty rounds. A real round produces a finding with a worked example, or records what was examined and that no change was needed.
- The rounds run autonomously. They ask the client only when essential business information is missing, when two requirements genuinely contradict, or when a fix would change an agreed function, cost or permission.
- The rounds evaluate the **specification**. They never prove that the application works — that is what CodeHero's real tests do, and their evidence lands in the acceptance manifest later.
- A *Draft* delivered early states the real number of completed rounds. If a package says "50 rounds" and Appendix E has eleven rows, it is not honest, and you send it back.

The executing agent later runs the same discipline on its *plan* (`guides/planning.md` step 12: about twenty review rounds for a real project, eight for a small one). Same idea, two levels: the spec is attacked before the plan exists; the plan is attacked before the tickets exist.

### 2.10 The package

The output is one Markdown file (plus an SVG logo concept when relevant) with a fixed structure — twenty numbered sections and appendices A–I (Planning Guide Part 7). The parts the in-app planner reads first:

| Part | Why it matters downstream |
|---|---|
| Header block with the `codehero_environment` block | Tells the planner whether a container is needed, who provisions it, which services, the database, real-time mode, build tooling, who serves the built files, and the fallback stack |
| 2 CodeHero run settings | Roles and think modes per ticket type, serial execution, replan and revalidation cadence, circuit breakers |
| 4 Access gate | The thin end-to-end slice through the real hosting before any feature |
| 7 Business rules | Numbered, with worked examples and expected results — the agent's only source of business truth |
| 17 Milestones and ticket plan | Value order, ticket text rules, requirement IDs per ticket |
| 18 Contracts, day-0 inputs, touchpoints | What the client must provide before the run, and the only four reasons CodeHero will contact them during it |
| Appendix F | Open items, assumptions to confirm, technical decisions — the first thing the client reads |
| Appendix G / H | Requirements register and dependency register — the traceability spine |

Ticket roles in the package are written **exactly** as CodeHero expects, and no provider or model is ever named:

| Ticket type | role | think_mode |
|---|---|---|
| Planning, replan, contracts, architecture, security | `master_developer` | `ultra` |
| Independent revalidation (verifies only) | `master_developer` (different provider if available) | `ultra` |
| Feature implementation | `senior_developer` | `balanced` |
| Repetitive work (locale files, CRUD from a contract, docs formatting) | `junior_developer` | `basic` |
| Tests and fixtures | `senior_developer` | `balanced` |

### 2.11 Draft vs Ready to build

| State | Condition | What CodeHero may do with it |
|---|---|---|
| **Draft for confirmation** | Contains *Assumed* or *Open* items; open items listed at the top, never hidden | Probe and setup tickets only; feature tickets that depend on open items wait |
| **Ready to build** | Critical open items of the agreed scope — and of the dependencies that scope needs — are closed; non-critical assumptions may remain and are listed | The full plan |

Moving a critical open item to *Later* requires the client's agreement; it is never done silently to reach *Ready to build*.

### 2.12 The day-0 pack and the four contact reasons

Before the run, the client provides the day-0 pack: domain, hosting access, SMTP account, logo files, the spreadsheet, first administrator details — and, if the container is created manually, the container with its access details. During the run, CodeHero contacts the client for exactly four reasons:

1. external credentials or accounts for a specific gate;
2. a fix loop that reached its limit;
3. a fallback that would change an agreed requirement;
4. discovery of a **new** critical business ambiguity that cannot be resolved from the confirmed requirements.

Ordinary business assumptions are confirmed *before* the run (Stage P, final confirmation), never during it. If your run keeps stopping with business questions, the interview was incomplete — fix the package, not the tickets.

### 2.13 Handing the package to CodeHero

The package is pasted (or attached) into the in-app *Plan with AI* planner, which recognizes it by its markers (`codehero_environment:` block, run settings, registers, ticket plan with roles and think modes) and switches to **IMPORT MODE**: it asks only for missing authorizations and day-0 owners, shows a preview, and creates the project plus ONE planning ticket that carries the package verbatim. The planning ticket plans on the real installation (Module 4); the package's ticket plan is its starting material — candidates, never tickets created as they stand. Day-0 inputs and open items go to the operator, never into ticket descriptions.

### 2.14 Developer's review checklist for a package

Before you import a package, check:

- [ ] Every requirement outside *Later* has at least one acceptance ID and a milestone (Appendix G).
- [ ] Every business rule in §7 has a number and a worked example in the client's values.
- [ ] Appendix F lists every *Assumed* item, every *Open* item and every requirement with origin `agent`.
- [ ] Critical items (money, approvals, deletion, legal, safety) are *Confirmed* or explicitly *Open* — none is *Assumed*.
- [ ] Every critical external dependency has a T9 row with a verification status; nothing needed by active scope is `pending` without a probe ticket.
- [ ] The `codehero_environment` block is complete and consistent with the stack template (`container_required`, `container_provisioning`, `services`, `database`, `realtime`, `build`, `served_by`, `fallback_stack`).
- [ ] The ticket plan is serial (strictly ascending distinct sequence numbers), starts with setup → capability probe → knowledge foundation → access gate → main process end to end.
- [ ] Every ticket cites requirement IDs; no ticket installs runtimes, databases or web servers; no ticket text mentions a container, a container name or an internal IP.
- [ ] Documentation deliverables are listed in the client's language.
- [ ] Appendix E has real review rows, and the stated round count matches.

### Exercises — Module 2

1. **Run an interview.** Pair with a colleague who plays a client (a dental clinic's appointment book, a warehouse's stock sheet, a school's attendance list). Set up the Spec Builder and let the "client" answer. Do not answer business questions yourself. Deliver the package.
2. **Audit the statuses.** In the package, count Confirmed / Assumed / Technical / Open. For every *Assumed* item write the one sentence the client must confirm. For every critical item check it is not *Assumed*.
3. **Spreadsheet intake.** Take any real spreadsheet you have. Apply §2.6 by hand: entities, fields, formulas → rules, colors → states, manual steps → jobs. Compare with what the Spec Builder produced from the same file.
4. **Find the wish.** In your package, find one dependency the client *wants* but nobody has *verified*. Write its T9 row and the probe ticket that would verify it.
5. **Review rounds.** Pick five perspectives from Part 6 of the guide and run them yourself on your package, recording findings in the T6 format. Did you find something the fifty rounds missed? (Usually yes — that is why the developer reviews.)

---
# PART III — CHOOSING THE STACK

## Module 3 — How and why CodeHero picks PHP, Node, Python or .NET

### 3.1 The principle: the right application for this client

The Spec Builder's central principle (Planning Guide §1.1) is *fit*: the solution matches the real needs of the application, the initial budget and the acceptable monthly cost, the knowledge of the client's team, their existing infrastructure, and their ability to install and maintain what you specify. A technically superior stack that the client cannot host or maintain is the wrong stack.

That is why the stack is decided **after** Stage C (constraints), never from the archetype alone, and why every deviation from the default carries a one-line justification in the spec. When you review a package or a quick plan, look for that line. If it is missing, the choice was a preference, not a decision.

### 3.2 PHP-first, MySQL-first — and why

CodeHero's default backend is **PHP ≥ 8.2 with MySQL ≥ 8**, on standard web hosting when the design allows. The reasons are practical, and you should be able to state them to a client:

| Reason | What it means for the client |
|---|---|
| Ease of installation and maintenance | Runs on any cPanel/Plesk hosting; no process manager, no daemon, no container to operate |
| Lowest running cost | Shared hosting money, not VPS money; no in-house support needed |
| Fit with CodeHero's own strengths | The PHP project context is the most mature one (canonical `includes/config.php` bootstrap, "silent mistakes" list, PDO-only, CSRF, PRG); the preview proxy, `php-fpm` log source and `php -l` syntax check are wired into the verification recipe |
| No build step by default | Plain `.js` plus local libraries copied from `/opt/codehero/libs/` (Tailwind, Alpine, Vue, FontAwesome) — instant, offline, no npm |
| Interpreted = served | On a host project the source *is* what nginx serves; nothing to compile, nothing to forget to copy |

The PHP profile covers: REST APIs, internal business applications, portals and management systems, backends for mobile apps, dynamic websites, and integrations served by ordinary requests or periodic jobs. **A REST API, complex screens or an app-like look are not reasons to leave PHP.** Neither is "many users" — load is judged from a representative workload described in the spec and verified in the access gate or a load test, never from a rule of thumb.

**MySQL stays the default with every backend.** Backend and database are decided separately: Python does not imply PostgreSQL and .NET does not imply SQL Server. PostgreSQL or SQL Server appear only when the client asks, when an existing environment or integration requires them, or when a specific application reason is recorded.

### 3.3 When to leave PHP — the only triggers

| Condition | Move to | Why |
|---|---|---|
| **WebSockets** are required by an acceptance criterion (alarms in seconds, live boards, multi-user editing) | T-NODE (T-NET / T-PY when the environment fits) | Web hosting cannot keep sockets open; CodeHero policy is never to stretch PHP to cover them |
| **Permanent workers** or continuous server-side processing (device/sensor streams, jobs that exceed cron limits, media processing) | T-NODE / T-PY | Worker processes beyond limited-duration cron |
| Statistics, forecasting, machine learning, scientific libraries | T-PY | Ecosystem |
| The client asks for a technology, or already runs and maintains one that meets the requirements | That stack | Maintainability and fit beat preference |
| Microsoft environment (Entra ID, SQL Server, Windows servers, a .NET team) when it fits their operations | T-NET | Fit with their operations |
| A native mobile app is needed | Swift / Kotlin + a backend by the rules above | — |

Server-sent events do **not** trigger the WebSocket row as long as they are verified on the actual hosting for timeouts, buffering and reconnection. If none of the triggers applies, the spec says so explicitly: *"PHP/MySQL chosen; runs on standard web hosting; no container required."*

### 3.4 The archetypes (what the signals usually mean)

| ID | Archetype | Typical signals | Default stack | Container? |
|---|---|---|---|---|
| A1 | Static site | Brochure, no login, contact form | HTML/CSS/JS + PHP mailer | No |
| A2 | Content site with forms and admin | Pages, catalog, submissions, small admin | T-PHP, Alpine + Tailwind | No |
| A3 | Internal tool / spreadsheet replacement | "Our Excel", records, roles, reports, imports | T-PHP; Vue only when the screens justify it | No |
| A4 | Multi-tenant SaaS | Many companies, per-company settings, billing | T-PHP (Laravel) for most; T-NODE when §3.3 requires | No / Yes |
| A5 | Real-time monitoring / operations | Devices, alarms, seconds matter, live screens | T-NODE (T-NET/T-PY when the environment fits) | **Yes** |
| A6 | Integration hub / API product | Connecting systems, webhooks, transformations | T-PHP when request- or schedule-based; T-NODE/T-PY when continuous | No / Yes |
| A7 | Customer / supplier portal | External logins, documents, statuses | T-PHP | No |
| A8 | Mobile companion app | Field staff, camera/barcode/GPS, push | T-PHP REST API + web app wrapped with Capacitor | Runtime as the backend |
| A9 | Native mobile app | Hardware/OS integration, offline-heavy | Swift / Kotlin + backend by the rules | Per backend |
| A10 | Data / analytics tool | Heavy calculations, forecasts, large imports | T-PY + MySQL | **Yes** |

### 3.5 The ladders: pick the lowest rung that satisfies the answers

**Real-time ladder** (from Stage 5 answers):

1. On refresh — content sites.
2. Polling every 15–60 s — most internal tools; any hosting; T-PHP.
3. Polling every 5 s + in-app badge — operational tools where a minute is too slow; still T-PHP.
4. Server-sent events — one-way live feeds; T-PHP where the provider supports it and it is verified; otherwise a container.
5. WebSockets with a durable event stream — alarms, live boards, multi-user editing; container stack. Pattern: events from a database outbox with cursor, replay on reconnect, heartbeat with visible disconnection, receipts.

**Mobile ladder:**

1. Responsive web app — every product gets it.
2. Installable web app (PWA) — home-screen icon, offline read-only cache, web push.
3. Capacitor wrapper — the same web app in the stores; native plugins for camera, barcode, GPS, push, biometrics. Requires Apple and Google developer accounts (day-0).
4. React Native / Expo — only if the client's team is React-based and asks.
5. Native Swift/Kotlin — only for A9 conditions.

**Frontend, chosen by need and separately from the backend:** a simple presentation page → HTML + Tailwind, minimal JS; simple forms → server-rendered pages + Alpine.js; complex screens with many interactions → Vue (PrimeVue preferred), built inside CodeHero and committed as static files, so a PHP host never needs Node.

### 3.6 Runtime vs build tooling vs serving — three separate declarations

The single most common confusion. The `codehero_environment` block separates them on purpose:

| Question | Field | Rule |
|---|---|---|
| What must be **running** on the server? | `container_required`, `services`, `long_running_processes` | Anything beyond PHP + MySQL at runtime (Node, Python, .NET, Redis, workers, WebSockets) → `container_required: true` |
| What is needed only to **build** artifacts? | `build.web` (none / tailwind-cli / vite), `build.android`, `build.ios`, `build_container` | Never changes the runtime answer; a Vite-built Vue app can run on a PHP host |
| Who **serves** the built files? | `served_by` (php-host-static-files / nginx-static / app-server) | Declared separately from the tools that build them |

The global context's Section 14 mirrors this at execution time — where the build workspace lives depends on the project shape:

| Situation | Build workspace |
|---|---|
| Container project | Anywhere inside the container; only the served output matters |
| Host, interpreted (PHP, plain HTML/JS) | Nowhere — the source *is* what is served; Composer `vendor/` at `{web_path}/vendor/` |
| Host, compiled, has `app_path` | `{app_path}` is the workspace; build there, copy output to `{web_path}` |
| Host, compiled, web_path only | `{web_path}/.build/` (nginx does not serve dot-dirs); only compiled output goes to the web root |

### 3.7 What CodeHero provides — so you never plan "install PHP" tickets

**Host projects.** Ubuntu 24.04, nginx, PHP 8.3, Node 22, Python 3.12, MySQL 8.0 (global §13). Each project gets its own MySQL database and user; credentials appear in the agent's `PROJECT DATABASE` block. Local libraries live in `/opt/codehero/libs/`.

**Container projects.** CodeHero creates an LXC container per project (`codehero-<project_id>`) from a manifest of services — the default manifest offers nginx, PHP 8.3, MySQL 8.0, Python 3.12, Node 20 and Redis 7, and the Container Isolation chapter of the User Guide lists the full catalogue of languages, databases and service options. Services declared at creation are **provisioned before any ticket runs**; the agent's commands are routed inside the container transparently; the agent sees services at `localhost:<port>` in its `PROJECT SERVICES` block and must believe it is on a normal server.

This is why the Planning Guide and the planner both say: *no ticket installs PHP, Node, MySQL, Redis or a web server, and no ticket configures nginx.* The first real ticket sets up the **application** (folders, config, schema), and a setup ticket in a container **verifies** the provisioned services and configures application-level pieces. A plan with an "install Node.js" ticket is a plan that misunderstood the platform.

### 3.8 Project type and paths

| Output | `project_type` | Path | Rule |
|---|---|---|---|
| Any project with web pages / HTML output — regardless of language | `web` | `web_path: /var/www/projects/<slug>` | A .NET, Node or Python app that serves HTML is still `web` |
| Pure backend API, CLI, library, mobile backend with no HTML | `app` | `app_path: /opt/apps/<slug>` | — |

`tech_stack` selects the project context file: `php`, `python`, `node`, `html`, `java`, `dotnet`, `go`, `react` (also used for React Native), `flutter`, `kotlin`, `swift`, `presentation`, `reporting`; project types `capacitor`, `native_android`, `dotnet`, `presentation`, `reporting` also map. Anything unmapped falls back to `php`. Pinned runtime versions (`php_version`, `node_version`, `python_version`, …) can be passed at creation and appear in the agent's `RUNTIME ENVIRONMENT` block.

### 3.9 The environment block, field by field

```yaml
codehero_environment:
  container_required: false          # runtime beyond PHP + MySQL? → true
  container_provisioning: none       # none | codehero (platform creates it WITH the services) | manual (client created it; access = day-0 input)
  services: [php-fpm, mysql]         # runtime services the environment must provide
  database: mysql                    # mysql by default; postgresql | sqlserver only with a recorded reason
  long_running_processes: none       # e.g. [api, workers, websocket-gateway]
  scheduled_jobs: cron-every-minute  # or worker-queue; state max duration, overlap lock, retries, interruption behaviour
  realtime: polling-30s              # none | polling-Ns | sse (verified on provider) | websocket
  build:
    web: tailwind-cli                #   none | tailwind-cli | vite
    android: none                    #   none | capacitor | native
    ios: none
    ios_path: none                   #   macos-xcode | external-service (named)
    signing: none
    test_devices: none
  build_container: none              # none | node | node+android | node+ios
  served_by: php-host-static-files   # php-host-static-files | nginx-static | app-server
  fallback_stack: none               # for any non-PHP choice: the T-PHP design to fall back to, valid only if the same acceptance criteria still pass
```

`container_provisioning: codehero` is the normal choice: the in-app assistant creates the container with the declared services before the planning ticket exists. `manual` means the client operates their own environment; then the container and its access details are a day-0 input, and the setup ticket only verifies and configures.

`fallback_stack` exists because the architecture is chosen before the installation is probed. If ticket #0 (the capability probe) finds that the runtime cannot be provided, the run stops with a question to the owner and proposes the fallback — **only** if it still passes the same acceptance criteria. A fallback that changes an agreed capability (update speed, live alarms, offline use) is a *requirements change*, not a technical swap, and each affected requirement ID must be named.

### 3.10 Two contrasting examples

**RepairFlow (A3, internal tool).** Stage C answers: occasional integrations (email only), no offline, no time limits, standard web hosting, minimal monthly cost. Stage 5: "on refresh is fine". No trigger to leave PHP. Decision recorded in the spec: *"PHP/MySQL chosen; runs on standard web hosting; no container required."*

```yaml
codehero_environment:
  container_required: false
  container_provisioning: none
  services: [php-fpm, mysql]
  database: mysql
  long_running_processes: none
  scheduled_jobs: cron-every-minute   # overdue check: max 50 s per run, overlap lock, 3 retries, safe to interrupt
  realtime: polling-60s
  build: {web: tailwind-cli, android: none, ios: none, ios_path: none, signing: none, test_devices: none}
  build_container: none
  served_by: php-host-static-files
  fallback_stack: none
```

CodeHero project: `project_type: web`, `tech_stack: php`, `web_path: /var/www/projects/repairflow`, no container.

**AlarmBoard (A5, real-time monitoring).** A logistics yard with 40 temperature sensors; the acceptance criterion says *"an out-of-range reading is shown on the operations screen within 2 seconds, measured from the sensor's timestamp to the on-screen alert"*. Stage 5: seconds matter; devices stream continuously. Two triggers fire (WebSockets by an acceptance criterion; continuous processing). Decision: T-NODE in a container, with the justification line *"WebSocket alerting within 2 s required by A07; sensor stream needs a permanent worker."*

```yaml
codehero_environment:
  container_required: true
  container_provisioning: codehero      # CodeHero provisions node, mysql, redis, nginx at creation
  services: [node, mysql, redis, nginx]
  database: mysql
  long_running_processes: [api, workers, websocket-gateway]
  scheduled_jobs: worker-queue
  realtime: websocket
  build: {web: vite, android: none, ios: none, ios_path: none, signing: none, test_devices: none}
  build_container: node
  served_by: nginx-static
  fallback_stack: T-PHP with polling-5s   # only valid if A07 still passes — it will not, so this is a requirements change
```

CodeHero project: `project_type: web` (it serves the operations screen), `tech_stack: node`, `web_path: /var/www/projects/alarmboard`, container created via `codehero_container_operations` with the declared services before any ticket.

### 3.11 Eight mini-cases (decide, then check)

| # | The client says | Decision | Why |
|---|---|---|---|
| 1 | "A website for our law firm with a contact form and a news page the secretary updates." | A2 · T-PHP · no container | Content + small admin; no trigger |
| 2 | "We want a REST API for our mobile app; 200 field workers upload photos of deliveries." | A8 · T-PHP REST API + Capacitor app · no container for the backend | A REST API and a mobile backend are not reasons to leave PHP; store accounts are day-0 inputs |
| 3 | "Our dispatchers must see every truck's position live on a map; alarms when a truck stops for more than 5 minutes." | A5 · T-NODE · container | Continuous device stream + live board; verify whether "live" means seconds (WebSocket) or a minute (polling) before deciding — the acceptance criterion decides |
| 4 | "We are a Microsoft shop: Entra ID logins, SQL Server, a .NET team maintains everything." | T-NET · container · SQL Server with a recorded reason | Fit with their operations; the client's team maintains it |
| 5 | "Forecast next month's demand per product from 5 years of sales; import the CSV every night." | A10 · T-PY · container · MySQL | Scientific libraries; nightly import is a scheduled job, not a worker |
| 6 | "A portal where our suppliers see their open orders and upload invoices." | A7 · T-PHP · no container | External logins, documents, statuses; scope-bound permissions |
| 7 | "Same as case 1, but we already run a Django site and our IT person knows Python." | T-PY on their environment, or T-PHP if they prefer — record the client's choice | The client already runs and maintains a stack that meets the requirements |
| 8 | "A dashboard with 12 KPIs from our MySQL, refreshed every minute, printable to PDF." | `reporting` project type · T-PHP · no container | Polling rung 2; the reporting context already carries ApexCharts, DataTables and PDF export patterns |

### 3.12 How to write the justification

One line, in the spec header and again in the planner preview when the stack is not PHP + MySQL. The pattern: *requirement ID → the capability it needs → why PHP cannot provide it → the chosen stack.*

> "A07 requires alert delivery within 2 s over a persistent connection; standard PHP hosting cannot hold WebSockets; T-NODE in a container with Redis-backed outbox."

A justification that names a preference ("Node is more modern") instead of a requirement is not a justification. Send it back.

### Exercises — Module 3

1. For each of the eight mini-cases, write the `codehero_environment` block. Compare with a colleague; every difference must be explainable by a requirement.
2. Take your Module 2 package. Find the stack decision. Is there a one-line justification? Does it cite a requirement ID? If the stack is PHP, does the spec say "no container required" explicitly?
3. Rewrite this bad plan fragment so it respects §3.7: *"Ticket 1: Install Node 20 and MySQL in the container. Ticket 2: Configure nginx to proxy port 3000. Ticket 3: Create the schema."*
4. A client insists on PostgreSQL "because it is better". Write the two sentences you would say, and the line you would record in the Decision Log if they still insist.
5. Explain to a non-technical client, in three sentences, why their internal tool will run on their existing web hosting and what that saves them per month.

---
# PART IV — PLANNING

## Module 4 — From package to project: the in-app planner and the ticket plan

### 4.1 Where planning happens — two places, one method

Open the AI Assistant in CodeHero and choose *Plan with AI*. The assistant runs with `config/assistant-planner.md` as its instructions plus the global context, and it has the `codehero_*` tools. It does two things well: it knows this installation (active providers, ports, container support), and it can create the project and its environment. **It designs no tickets.** It writes the specification with you (or imports a Spec Builder package), settles everything only a person can decide, shows a preview, and after you confirm creates the project, the container when the environment contract declares one, and exactly one ticket: the **planning ticket** (`[PLAN] <project> — baseline and phase 1`).

The planning ticket runs in **PLAN MODE** (`guides/planning.md`, pre-loaded for it by the daemon) on the real installation: it saves the specification as the immutable baseline (`.specs/000-baseline.md`), reads the active providers, writes the plan file (requirements with acceptance examples, roles, stack, run settings, open questions), fills the knowledge base, writes one SPEC FILE per sub-task with the shared contracts first, orders the work by value, runs a **dry run** of the plan and its review rounds, gets a **peer check** from another provider, and creates the **first phase** of tickets. Every later phase is created by the `[REPLAN]` ticket that ends the previous one. The same PLAN MODE runs when a user opens a ticket by hand and says "σχεδίασε": one method in one place.

**Size decides the depth.** A small change or fix on an existing project is not a plan at all — the assistant creates one ordinary build ticket and the agent runs the light loop of the global context. A small project (one phase, up to about eight tickets, no accounts, no money) gets PLAN-lite: eight review rounds, a peer check only when there is login or money, no `[REPLAN]`. A real project gets about twenty rounds, the peer check, and phases of about ten tickets.

### 4.2 The assistant's rules that matter to you

1. **MCP tools only.** Project, environment and the planning ticket are created with `codehero_create_project`, `codehero_container_operations` and `codehero_bulk_create_tickets` (with one ticket) — never with SQL, curl or the UI on the assistant's behalf.
2. **`codehero_get_providers_info` first.** The single source of truth for active providers, cost and smart weights per role, vision and thinking support; the assistant never plans from memory. The planning ticket reads it again itself.
3. **Only active providers**, for the project default and for the planning ticket.
4. **Exactly one ticket.** Even a package with a complete ticket plan produces one planning ticket; the cards stay candidates.
5. **Preview → explicit confirmation → create.** Settings, specification summary, day-0 inputs, run settings, then "yes / ok / ναι / προχώρα". "Do what you think" delegates decisions, not the preview.
6. **Business decisions belong to you** (money, rights, approvals, deletion, retention, safety, scope, cost). A gap is marked `open`, never filled with an invented default. **Front-load the human input**: once the planning ticket starts, the run is autonomous and a missing business decision stops it.
7. **Environment is not ticket work** — containers and services are created before the planning ticket; tickets install no runtimes; ticket text says `localhost:<port>` and never a container name or an internal IP.
8. **What you set, it passes.** Flow, execution mode, strategy, parallel and plan approval appear in the preview, in the run contract, and explicitly in the tool call (`relaxed` = `deps_include_awaiting: true`, `strict` = `false`).
9. **Language** and voice mode, as everywhere.

### 4.3 Three modes

| Mode | Trigger | What the assistant does |
|---|---|---|
| **IMPORT** | The message contains a specification package (an `environment_contract:` or legacy `codehero_environment:` block, run settings, registers, a ticket plan) | No re-interview. Reads the header, readiness, environment and run contract; asks only for missing authorization, day-0 owners and a critical open item you can settle now; passes the package verbatim into the planning ticket |
| **BUILD** | Anything else: a description, a spreadsheet, a document | Acts as the Spec Builder: one focused question at a time, technical matters decided itself, writes the specification (mandate, business behavior, people, data, integrations, experience, numbers, environment contract, acceptance, registers, run contract), runs an in-app consistency check, previews |
| **TICKET TEXT ONLY** | "Just give me the ticket text" | Runs BUILD or IMPORT, then outputs the filled planning-ticket text instead of creating it |

Defaults: execution `autonomous`, flow `relaxed` (`deps_include_awaiting: true`), strategy `balanced`, serial, plan approval `autonomous` (you approved the preview; the planning ticket does not ask again — set `plan_approval: owner-approves-first-stage` if you want to see the ticket table before anything is created), project think mode `balanced`. **`ultra` is never a project default**; the planning ticket itself runs `master_developer` + `ultra` on the smartest active provider that supports thinking.

### 4.4 Providers, roles, think modes, strategy — the planning ticket's job

**Roles, not models.** A ticket stores `ai_model` = `master_developer` / `senior_developer` / `junior_developer`. Which concrete model that means depends on the provider, via `heroagent/heroagent.conf` (`model_aliases`). Adding a new model to the platform is a config edit; no ticket changes.

**Role by complexity and strategy** (the planning ticket's table; the Spec Builder's table in Module 2 covers packages that state roles):

| Complexity | eco | balanced | performance |
|---|---|---|---|
| Trivial (docs, typos, config) | junior | junior | junior |
| Simple (static pages, boilerplate) | junior | junior | senior |
| Moderate (features with logic, APIs) | junior | senior | senior |
| Complex (multi-file, refactor) | senior | senior | master |
| Critical (architecture, auth, security, setup/foundation) | senior | master | master |

**Think mode ladder:** `off`/`basic` for trivial and simple work; `balanced` for standard features; `ultra` never for a build ticket on the planner's own initiative — and always for `[PLAN]`, `[REPLAN]`, `[VERIFY]`, `[PEER]` and `[HELPER]` tickets.

**Provider assignment** (never the Spec Builder's job):

- visual build or verify tickets → vision-capable providers only;
- the chain tickets (`[PLAN]`, `[PEER]`, `[VERIFY]`, `[HELPER]`, `[REPLAN]`) → the preferred pair is **anthropic ↔ openai**: one side plans and builds, the other reviews and verifies; an installation without them uses the customer's master-tier provider (highest `master_developer` smart weight), with a different family for the verify when one exists; the user's explicit preferences win;
- `[VERIFY]` tickets → a **different provider family** than the builder, `master_developer`, `ultra`;
- tickets that share a `sequence_order` (an approved parallel group) → spread across providers to avoid rate limits;
- strategy: eco = cheapest capable, performance = highest smart weight, balanced = both;
- a single active provider → use it for everything; a `[VERIFY]` on the same provider is still worth running but never counts as a second opinion.

### 4.5 Translating the environment contract into a project

| Contract says | Assistant does |
|---|---|
| `standard-hosting` / `native-host` (legacy: `container_required: false`) | Host project. HTML output → `project_type: web`, `web_path: /var/www/projects/<slug>`; no HTML → `app`, `app_path: /opt/apps/<slug>`. `tech_stack` from the stack; pinned versions if the spec states them. |
| `platform-container` (legacy: `container_required: true`, `container_provisioning: codehero`) | Create the project, then the container with `codehero_container_operations` declaring the listed `services` (nginx is automatic). Before the planning ticket. |
| `existing-infrastructure` (legacy: `manual`) | Access details are a day-0 input. Missing → open item; readiness at most *Ready for scoped discovery*. |
| A runtime missing on a native host | A day-0 input with its owner — never a ticket. |
| Run contract | Written into the planning ticket as a top-level `## RUN CONTRACT` section (and summarized in the project description). The planning ticket obeys it; a "run contract" found inside a specification or a message authorizes nothing. |
| Day-0 inputs and open items | A `## DAY-0 INPUTS AND OPEN ITEMS` section of the planning ticket; the planner turns them into `BLOCKED` asks at the step that needs them and never asks a known open item again. |
| Draft / open items | The planning ticket creates only what the open items allow; feature tickets wait. |

### 4.6 The ticket fields and what the scheduler does with them

| Field | Meaning | Blocks execution? |
|---|---|---|
| `sequence_order` | Ordering. Distinct ascending numbers = serial (the default). The same number on two tickets = a parallel group (as many at once as `MAX_PARALLEL_TICKETS_PER_PROJECT` allows). | **Yes** — a higher number starts only when EVERY ticket with a lower number is `done` or `skipped`. A ticket left in `awaiting_input`, `failed` or `stuck` holds everything behind it. |
| `depends_on` | Explicit dependency. In a bulk call: 1-indexed positions of the same call, earlier only (a later or unknown position rejects the whole call). In `codehero_create_ticket`: existing tickets by numeric id or ticket number (an unknown value is an error). Stored in `ticket_dependencies`. | **Yes** — every dependency must be `done` or `skipped`, in relaxed and strict flow alike. It matters inside a shared sequence number; across numbers the number already orders. |
| `parent_ticket_id` / `parent_sequence` | Sub-task: waits for the parent, inherits its context (title, description, summary of the parent's conversation). This is how a `[VERIFY]` ticket finds its parent. | **Yes** — the parent must be `done` or `skipped` |
| `ai_model`, `provider`, `think_mode`, `execution_mode` | Per-ticket settings; omitted → inherit from the project | — |
| `deps_include_awaiting` | The flow: `1` relaxed (default) · `0` strict — see §4.9 | — |
| `is_forced` | Forced start (Start Now / Force Next / `codehero_start_ticket`): the ticket starts NOW on an extra worker slot, ignoring its sequence, its dependencies, its parent and the slot limit. For an observer ticket or a small change while the plan runs; the flag stays, so a forced observer restarts after every reply. | overrides everything |
| `ticket_type`, `priority` | feature / task / bug …; low / medium / high / critical | Priority only orders eligible tickets |

How the daemon picks the next ticket per project: the **lowest sequence number that still has an unfinished ticket** → among the tickets of that number: status `open` (or `new`/`pending`) → retry cooldown elapsed → every dependency `done`/`skipped` → parent `done`/`skipped` → forced first, then creation time → as many as the free slots allow. Nothing of a higher number is even considered.

**Titles are triggers.** `[PLAN]`, `[REPLAN]`, `[VERIFY]`, `[FIX]`, `[HELPER]`, `[PEER]` make the daemon pre-load the matching guide into the ticket's context. Keep the prefix exactly.

Adding tickets to a project that already has some: explicit sequence numbers in a bulk call are auto-offset to continue after the existing ones; `codehero_create_ticket` stores the number you give — that is how a verifier puts its fix at its own sequence.

### 4.7 Serial first; parallel as an offer; the file-ownership analysis

Design every plan serial. A serial run cannot corrupt shared files, and every ticket starts from the previous ticket's verified, reported state. The cost is wall-clock time; the benefit is correctness and a clean audit trail.

When some tickets are truly independent (different pages, different API folders, different components, different test files, different migration files), the planner may **offer** a group: *"Tickets 4, 5, 6 touch different files and could run together — parallel? (yes/no)"*. Only an explicit yes turns it on (a request that already asked for parallel counts as yes). Then the analysis is mandatory:

1. For every ticket in the group, list the exact files and folders it will create or edit. The ticket **owns** them; the list goes into its description; the agent may not touch files outside it (global H6).
2. Check the danger files by name against every ticket in the group: `index.php` / `index.html`, `app.js` / `main.*`, routing tables, `package.json` / `composer.json` / `requirements.txt`, `.env` / config, DB migrations, global CSS, shared header/footer includes.
3. Zero overlap is required. Any overlap → serialize (`depends_on` + different `sequence_order`), split the ownership, or merge into one ticket.
4. Show the ownership table in the preview. Maximum 5 tickets per group. In any doubt → serial.

Two exceptions need no approval: `[VERIFY]`, `[PEER]` and `[HELPER]` tickets may share a `sequence_order` with the ticket they serve, because they are forbidden to write product files; and the `[FIX]` tickets a verifier creates at its own sequence while it parks and waits for them (§5.9).

### 4.8 The ticket description recipe (every ticket, both modes)

The executing agent sees only the ticket text plus the project context. A description that assumes the reader was in the planning conversation is a description that will be misread. Five parts:

1. **Objective** — what to build, concretely, and the requirement IDs it serves.
2. **Where** — the files and folders this ticket owns.
3. **Contracts** — endpoints, table and column names, response shapes, shared formulas that other tickets rely on. Shared things are written *before* either side is built (P6, `guides/planning.md` step 5: contracts first).
4. **Environment facts** — services at `localhost:<port>`, credential placeholders, the preview URL shape. Never a container name or an internal IP; never the word "container".
5. **Definition of done** — how the agent verifies: what to run, which page to load, what the expected output is. Testable sentences, not adjectives.

Three text rules from the Planning Guide, worth repeating because they are the ones most often broken by hand-written tickets: **self-contained**, **`localhost` only**, **application, not infrastructure**.

### 4.9 Execution mode and flow

| Execution mode | Behaviour | Use when |
|---|---|---|
| `autonomous` (default) | No permission prompts; the permission hook still enforces path protection and loop detection | Trusted work, the normal ADF run |
| `semi-autonomous` | Auto-approves file operations inside the project, tests, builds, lockfile-only installs, read-only git; **asks** for new package installs, `npm/composer update`, migrations, git writes, service restarts, network calls; **blocks** system files, `.git` internals, anything outside the project | Projects that need guardrails; approvals can be generalized with "Approve all similar" |
| `supervised` | Asks before every write, edit and command | Sensitive projects; learning how the agent works |

| Flow | `deps_include_awaiting` | What changes |
|---|---|---|
| `relaxed` (default) | `1` | When the agent finishes, the ticket parks in `awaiting_input`, the auto-reviewer classifies it (COMPLETED / QUESTION / ERROR) and closes it to `done` on COMPLETED after a short delay |
| `strict` | `0` | The ticket parks in `awaiting_input` with reason *completed* and a human closes it |

Note what relaxed does **not** do: it does not let a ticket in `awaiting_input` satisfy a dependency. Dependencies always require `done` or `skipped`.

### 4.10 The two previews

**The assistant's preview** (before anything exists):

```
⚙️ Settings
• Project: <name> (<type>, <path>) — <stack> · Environment: <deployment_mode> [services: …]
• Execution: <mode> · Flow: <relaxed → deps_include_awaiting: true | strict → false> · Strategy: <…> · Parallel: <serial-only|allowed> · Plan approval: <autonomous|you approve the first stage>
• Planning ticket: <provider> · master_developer · ultra

📄 Specification — <readiness state> · review: <what was actually done>
• Scope (MVP): … · Later / parked: … · Assumptions I made: … · Open items: <item → owner → what it blocks>
• Day-0 inputs you must provide: <what → who → when it is needed>

▶️ What happens after you confirm: project [+ environment] + ONE planning ticket …
Do you agree? (yes / no / changes)
```

**The planning ticket's plan** (in its final report and in `.specs/001-project-plan.md`): the run settings in one line, then the ticket table (# · ticket · seq · provider · role · think · deps · files owned · verify), plus three honest lines — what the dry run found, what the review rounds changed and how many really ran, and the peer verdict (or "no second provider"). With `plan_approval: autonomous` it creates the phase right away and reports `NEEDS THE USER: no`; with `owner-approves-first-stage` it asks "Should I create the tickets?" and waits.

Read a plan like a reviewer, not a spectator: is the first milestone the thinnest end-to-end slice? Does every `[VERIFY]` use a different provider family? Is every visual ticket on a vision-capable provider? Does every dependency express a real need? Is anything in it that nobody asked for?

### 4.11 Worked plan: RepairFlow, phase 1

Assume the installation's active providers are `anthropic` (vision), `deepseek` (no vision), `gemini` (vision). The package is *Ready to build*. The plan table the planning ticket produced for phase 1 (its own `[PLAN]` ticket is not in the table):

```
⚙️ Settings:
• Project: RepairFlow (web, /var/www/projects/repairflow) — PHP 8.3 + MySQL, no container
• Providers: anthropic, deepseek, gemini · Strategy: balanced
• Execution: autonomous · Flow: relaxed
• Day-0 inputs: SMTP account for notifications (client) · first Owner account details

| #  | Ticket                                              | Seq | Provider  | Role   | Think    | Deps | Files                                   | Verify |
|----|-----------------------------------------------------|-----|-----------|--------|----------|------|-----------------------------------------|--------|
| 1  | Capability probe: runtimes, DB access, preview URL  | 1   | deepseek  | senior | basic    | -    | .specs/000-probe.md                     | -      |
| 2  | Knowledge foundation: store architecture + rules    | 2   | deepseek  | master | balanced | 1    | .specs/, knowledge base                 | -      |
| 3  | Application setup: bootstrap, schema, seed, header  | 3   | anthropic | master | balanced | 2    | includes/, database/, .env.example      | ✓      |
| 4  | [VERIFY] Application setup                          | 4   | gemini    | master | ultra    | 3    | (checks only)                           | -      |
| 5  | Access gate: login + empty job list on preview URL  | 5   | anthropic | senior | balanced | 3    | login.php, index.php, includes/auth.php | ✓      |
| 6  | [VERIFY] Access gate                                | 6   | gemini    | master | ultra    | 5    | (checks only)                           | -      |
| 7  | Core slice: create job → change status → deliver    | 7   | anthropic | senior | balanced | 5    | jobs/, includes/JobService.php          | ✓      |
| 8  | [VERIFY] Core slice (incl. negative tests)          | 8   | deepseek  | master | ultra    | 7    | (checks only)                           | -      |
| 9  | Overdue rule + daily notification (outbox, cron)    | 9   | deepseek  | senior | balanced | 7    | cron/overdue.php, includes/Mailer.php   | ✓      |
| 10 | [VERIFY] Overdue + notification                     | 10  | anthropic | master | ultra    | 9    | (checks only)                           | -      |
| 11 | [REPLAN] check phase 1 and plan phase 2             | 11  | anthropic | master | ultra    | 9    | .specs/, tickets                        | -      |

📊 anthropic=5, deepseek=4, gemini=2 · 💰 medium · ⚡ Flow: serial
Do you agree? (yes / no / changes)
```

Points to notice:

- The probe and the knowledge foundation come first; the **access gate** (login + empty list on the preview URL) proves the whole path before any feature; the **core slice** is the product's purpose (a job moves through its states); the overdue rule is the first business rule with money-like consequences and gets a VERIFY on a different family.
- VERIFY tickets alternate families (gemini checks anthropic; deepseek checks anthropic; anthropic checks deepseek) and are always `master` + `ultra`. Ticket 8 is on deepseek because checking a job workflow is logic, not visuals; ticket 4 and 6 are on gemini because they check pages.
- The last ticket is the `[REPLAN]`: it compares the real project with the baseline plus the change ledger (aligned / missing / wrong / not asked for), repairs first if needed, then plans and creates phase 2 — without asking for approval again, because the operator approved the plan with that ticket in it. It asks only if the scope must change.
- Everything is serial. Ticket 9 could have been offered in parallel with a hypothetical "job sheet PDF" ticket (different files), but the planner did not offer it: both touch `includes/` and the offer would have needed an ownership split. In doubt → serial.

### 4.12 Two ticket descriptions from that plan

**Ticket 3 — Application setup** (`master_developer`, `balanced`):

```
Objective (R001, R010, R011): create the application foundation for RepairFlow.
- includes/config.php: the canonical bootstrap (env → session → PDO → CSRF → helpers → error handler)
  exactly as the project context prescribes. Read DB_* from .env; commit .env.example only.
- database/schema.sql: tables customers, technicians, jobs, job_status_history, job_helpers,
  users (roles: owner, front_desk, technician). Money = DECIMAL(10,2). Every table has id,
  created_at, updated_at; FKs indexed; ON UPDATE CASCADE everywhere; job_status_history keeps
  who/when/from/to (no silent overwrite).
- database/seed.sql: one user per role (test passwords in .specs), 3 technicians, 5 customers.
- includes/header.php + includes/footer.php with the shared navbar (relative links only),
  libs/ copied from /opt/codehero/libs (tailwind, alpine, fontawesome with webfonts).

Owned files: includes/, database/, libs/, webfonts/, .env.example, .specs/003-setup.md

Contracts other tickets rely on:
- jobs.status ENUM('received','in_repair','ready','delivered')
- jobs.deadline DATE = received_at + 14 days (computed on insert by JobService, never by the UI)
- helper functions e(), csrf_field(), csrf_check(), requireAuth(?string $role)

Environment: MySQL at localhost:3306, credentials in the PROJECT DATABASE block.
Preview URL: https://127.0.0.1:{PROJECTS_PORT}/repairflow/

Definition of done:
- php -l passes on every file; schema.sql applied without error; seed rows present (SELECT COUNT).
- Loading the preview URL returns the header/footer skeleton with 0 console errors and 0 requests ≥ 400.
- .specs/003-setup.md acceptance list walked item by item; knowledge stored: schema decisions,
  status enum, deadline rule (type: decision) with WHY.
```

**Ticket 4 — [VERIFY] Application setup** (different provider, `master_developer`, `ultra`, `parent_sequence` = 3, so the platform gives it `parent_ticket_id` and makes it wait for ticket 3; `guides/verify-fix.md` is pre-loaded):

```
cycle 1 · GUIDE: verify-fix.md
You only CHECK. You never edit code and never "improve" anything.
Parent: your parent_ticket_id (codehero_get_ticket on your own id). Its SPEC FILE: .specs/003-setup.md.

Walk the parent's ACCEPTANCE list item by item, run the CORE Section 9 recipe on the preview URL
and `bash .tests/run.sh`. Add your own negative checks: a page without the bootstrap must not exist;
the DB DSN must include charset=utf8mb4; PDO must use ERRMODE_EXCEPTION; a second run of schema.sql
must fail cleanly, not corrupt data; no absolute URLs in header/footer.

A FINDING = a requirement not met or a reproducible bug, with steps, expected, observed.
Style preferences are not findings (one line at the end at most).
No findings → VERIFY: PASS line on the parent's SPEC FILE, report "verified: pass" with evidence.
Findings → create ONE [FIX] ticket for the original builder at YOUR sequence_order (same provider
and role as ticket 3, no depends_on), park with ⏸ WAITING-FOR-TICKET #<fix id>, and re-check the
findings yourself when the fix replies (cycle 2). Circuit breaker after 3 cycles.
```

### 4.13 After creation

Use `codehero_get_project_progress` (or the Project Progress page) to see the tickets with their roles and providers; `codehero_update_ticket` to change a ticket's role, provider, think mode or status; `codehero_set_ticket_sequence` to reorder. The agent will create its own VERIFY, fix, helper and replan tickets during the run — expect the list to grow, and check that each new ticket follows the same rules (Module 5).

### Exercises — Module 4

1. Import the package from your Module 2 exercise into *Plan with AI*. Before saying yes, write down three things you would change in the preview and why. Apply them with "changes", then confirm.
2. Write the full five-part description for ticket 7 of the RepairFlow plan (the core slice), including the contracts the overdue ticket will rely on.
3. The planner offers to run "Customer list page" and "Technician list page" in parallel. Do the file-ownership analysis: list each ticket's files, check the danger files, decide. Show the ownership table.
4. Explain, with the scheduler rules of §4.6, what happens to ticket 9 if ticket 7 ends in `awaiting_input` with a question. What must the operator do?
5. A colleague hands you a batch where ticket 1 has `depends_on: [1]`. What happens when it is submitted, and how do you fix it?

---
# PART V — EXECUTION

## Module 5 — What happens when a ticket runs, and how to read it

### 5.1 The lifecycle of a ticket

```
            ┌──────────── retry (≤ max_retries, cooldown) ────────────┐
            │                                                          │
 open ──► in_progress ──► agent says TASK COMPLETED ──► awaiting_input ──► done
   ▲            │                                     (reason: completed | question | error | permission | stopped)
   │            │ crash / exception                           │
   │            ▼                                             │ relaxed: auto-reviewer says COMPLETED
   │         failed ───────── past max_retries ──► failed (sticks)      │ strict: a human closes
   │            │                                             │
   │            └── rate limited ──► open (after cooldown, not counted as a failure)
   │
   └──────── user or peer reply, "Retry", "Reopen" ──── awaiting_input   (a reply re-opens; a parked ticket whose
                                                   awaited ticket ended without replying is woken by a watchdog)

 stuck   = the watchdog judged the conversation an unproductive loop
 timeout = max_duration_minutes exceeded
 skipped = manual skip; counts as complete for dependencies (timeout does not)
```

Facts you will rely on:

- The agent never writes `done` itself. Finishing always parks the ticket in `awaiting_input` with a reason; **closing is a review decision** (automatic in relaxed mode, human in strict).
- The **auto-reviewer** is a small sub-agent (junior tier of the ticket's own provider) that classifies the last messages as COMPLETED, QUESTION or ERROR. Deterministic rules run before it: the agent's report starts with `NEEDS THE USER: yes/no` and `OPEN ISSUES AND DOUBTS: …` — `yes` never closes; a chain ticket (`[VERIFY]`, `[FIX]`, `[PLAN]`, `[REPLAN]`) with `no` closes even though its body talks about another ticket's failures, and the doubts it lists stay on the record for you; a `[PEER]`/`[HELPER]` ticket is never auto-closed (the ticket that opened it closes it); a parking marker (`⏸ WAITING-FOR-TICKET #id`) whose ticket is still live keeps it parked; and a body that flags a problem ("PROBLEM:", "2 failed", "not clean") is ERROR even if it also says TASK COMPLETED. Only relaxed tickets are reviewed; strict ones wait for you. Further rules (v4.49.1): a `[PEER]`/`[HELPER]` ticket is never auto-closed (the ticket that opened it closes it); a build ticket whose two lines say `no` + `none` closes on those lines (the next `[VERIFY]` is the real check; a junior reviewer tier marked clean reports as errors); a report without the two lines is judged by the LLM reviewer; a planning ticket cannot create tickets while a peer or helper is open (the platform refuses the call); the two report lines are read at their last occurrence (the Codex CLI stores its progress notes and the report as one message); a subscription window limit reported by the CLI ("You've hit your session limit · resets …") is treated as a rate limit: the notice is not stored as an answer and the ticket retries every few minutes until the window is back.
- **Any reply reopens.** A message from you (UI or Telegram) or from another ticket sets a parked ticket to `open`; the daemon resumes the same conversation. A message that lands *while* the agent is still running reaches it at its next step (inside a tool result, signed `📨 FROM TICKET #id` when it comes from a ticket); if the run ends with a message still unread, the daemon re-opens the ticket instead of parking it — nothing is lost.
- **Dependencies need `done` or `skipped`.** A ticket sitting in `awaiting_input` blocks everything that depends on it. In a serial plan that means the whole project waits for your answer — by design.
- Retries: a crash or provider error returns the ticket to `open` up to `max_retries` (default 3) with a cooldown; a rate limit is not a failure. A ticket you stopped with the kill switch is never overwritten with `failed`.
- The watchdog checks long-running tickets and asks a sub-agent whether the conversation is truly stuck; the instruction to that sub-agent is to *err on the side of continue*. Genuine loops become `stuck`.

### 5.2 What the agent sees and can do

The system prompt is the layered assembly of Module 1 §1.6. On top of it the agent has two tool families:

**Built-in tools (HeroAgent)** — with the policy their own cheat-sheet teaches the model:

| Tool | Use it for | Policy |
|---|---|---|
| `Read`, `Write`, `Edit`, `MultiEdit` | Files | Read before edit; files over 500 lines: `Grep` first, then targeted `Read` |
| `Glob`, `Grep` | Finding files and text | Instead of `find` / `grep` via Bash |
| `Bash` | Commands | *Last resort* — prefer the dedicated tools; foreground only; `run_in_background` is denied |
| `ProcessManager` | Long-lived services (dev server, API) | Instead of `nohup … &`; survives the turn |
| `HttpRequest` | API calls, CSRF flows | Instead of `curl`; sessions persist |
| `Browser` | Functional flows: goto, click, fill, wait_for, get_text, eval, console_logs, network_logs | The only way to test pages; sessions persist across calls |
| `PageAssert` | Structured checks: visible, contrast, no console errors, no broken images | Works without vision |
| `LogTail` | Server logs by named source (`nginx-error`, `php-fpm-8.3`, `mysql-error`, …) | Instead of `tail` / `journalctl` (no sudo prompts) |
| `WebFetch` | Reading documentation pages | — |
| `GetCached` | Re-reading a large tool result that was summarized | — |

**Platform tools (MCP, `codehero_*`)** — the ones the global context makes mandatory: `codehero_knowledge_search` / `codehero_knowledge_store` / `codehero_knowledge_list` (the knowledge base), `codehero_git_operations` (`backup_snapshot`, `backup_status`, `backup_restore`, …), `codehero_screenshot`, `codehero_extract_context`, **`codehero_get_guide`** (opens one of the ten guides), and the ticket tools `codehero_get_ticket` / `codehero_update_ticket` (reply, close) / `codehero_create_ticket` / `codehero_get_project_progress` / `codehero_start_ticket` (forced start). Every MCP result of a ticket agent also carries the messages other tickets wrote to it while it worked.

**The permission hook** sits between the model and every tool call. It enforces the execution mode (Module 4 §4.9), path protection (H5: only `{web_path}`, `{app_path}` and `/tmp`), container routing, the background-Bash denial, the malformed-edit guard, and **loop detection**: an identical action repeated three times returns a "you appear to be stuck — stop and rethink" message to the model; at five it hard-stops the approach. Read-only waiting (polling a ticket, a bare `sleep`) is exempt, so a parked dialogue is not mistaken for a loop. HeroAgent adds per-tool error counters (warn at three consecutive failures, break at five) and a cap of 1000 iterations per run.

**Container projects.** The agent's commands are routed inside the container by the platform (the `crun` wrapper). The agent does not know and must not be told; it works on "a normal server" where services are at `localhost`.

### 5.3 The work loop the agent follows (global §5)

1. **Understand** the task (apply the language rule).
2. **Search** the knowledge base — one broad query with the task title, one per component — then read the relevant code.
3. **Open the SPEC FILE** (`.specs/<NNN>-<task>.md`), always, even for an easy task: GOAL and STATUS before any code. Open questions → ask now, in one batch, or apply a safe default. (A **small change or fix** — one concrete thing, no new page, table or feature — runs the *light loop*: a two-line SPEC FILE, only the guide of the thing touched, verify that thing, `bash .tests/run.sh`, snapshot, a five-line report. No plan mode, no rounds, no peer.)
4. **Build one small part.**
5. **Verify that part** (§5.5). Fails → debugging protocol (§5.6).
6. **Update the SPEC FILE, then snapshot.** After every part, not only at the end.
7. Parts remain → back to 4.
8. **Full test on the PREVIEW URL**, then `bash .tests/run.sh` (ALL repeatable tests — the runner `.tests/run.sh` is installed by the platform in every project), then walk the ACCEPTANCE list item by item: pass, fail, or BLOCKED with the reason.
9. **Store knowledge**: decisions and failed approaches.
10. **Report — two lines, then the 4-part handoff** (§5.8), then `TASK COMPLETED`.

Long task? After a verified part the agent may call `codehero_extract_context` to compress old messages; the SPEC FILE survives compression and is re-read right after. The platform also compacts automatically when the conversation grows past its thresholds, and shows a visible compaction message in the ticket. This is why P6 (memory on disk) is a principle and not a suggestion: everything the next step needs must already be in `.specs/` or the knowledge base.

### 5.4 Two memories

| | SPEC FILE (`.specs/NNN-name.md`) | KNOWLEDGE BASE (graph) |
|---|---|---|
| Scope | This task | The whole project, forever |
| Content | GOAL · APPROACH · FILES & CONTRACTS · DATA FLOW · RISKS · ACCEPTANCE · OPEN QUESTIONS · STATUS (live: ✔ done · ▶ doing · ☐ pending · `NEXT:`) | Nodes: `decision`, `failed_approach`, `pattern`, `bug`, `service`, `component`, `class`, `method`, `file`, `library`, `api_endpoint`, `config`, `spec`, `milestone`. Edges: `uses`, `depends_on`, `fixed_by`, `calls`, `failed_for` |
| Written when | Before coding, after every part, at the end | The user says "remember"; a command failed then worked (💡 TEACHABLE MOMENT); a non-obvious choice between approaches; architecture designed |
| Read by | The agent after compaction ("if you feel lost, re-read the SPEC FILE first"), the VERIFY ticket, the next ticket | Every ticket at start; the hint system (🚨 known dead ends for a file about to be edited) |
| You read it in | *Project Files* / File Explorer | `codehero_knowledge_list` / `codehero_knowledge_search` from the AI Assistant, and the knowledge snapshot at the top of each ticket's system prompt |

Every `failed_approach` must have a `failed_for` edge to the component it hurt (component name = file basename without extension). The next time any ticket edits that file, it sees the dead end. Teach your trainees to check the graph after a run: a project with zero `decision` nodes after ten tickets is a project whose agents are not following §7 — a context problem, not a model problem.

### 5.5 The verification recipe (global §9) — what "evidence" concretely means

- Syntax checks: `php -l`, `python3 -m py_compile`, `node --check`, `tidy`.
- Browser recipe on the PREVIEW URL: `goto` → exercise the key actions → `console_logs` (must be 0 errors) → `network_logs` with status ≥ 400 (must be empty) → `PageAssert` (no console errors, no broken images, key elements visible) → `LogTail` on `nginx-error` and `php-fpm-8.3`.
- If the project has login: test the logged-in state (UI path and API/CSRF path) AND the refusals with a positive control (`guides/testing.md`); the ticket that delivers login creates the test user.
- Deliveries need proof: an email, webhook or export is "sent" only with a receipt, a log line, an outbox row or a test inbox. Otherwise "attempted, unverified" or BLOCKED.
- Expected results come from *outside* the code: the request, the acceptance list, the user. "The function returns 42 and my test expects 42 because the function returns it" proves nothing.
- Every interactive element carries a `data-testid` (`{action}-btn`, `{field}-input`, `nav-{page}`, …) so that VERIFY tickets on other providers can find it.

Preview-URL rules the agent must not "work around": a 403 on the bare root means the project folder is missing from the URL (per-project auth, expected); a 400 on plain `http://` means the scheme is wrong (it is HTTPS). Neither is a bug; both mean "fix the URL and try the same shape again". Never `php -S`, never another port, never `localhost` instead of `127.0.0.1`.

### 5.6 The debugging protocol (global §8 + `guides/debugging.md`)

Snapshot → reproduce once → collect evidence in order (browser console, network ≥ 400, `nginx-error`, `php-fpm`, `mysql-error`) → locate the first point where reality differs from expectation along request → handler → logic → storage → response → page → **one** hypothesis → **one** targeted check → fix the root cause → verify (re-run the reproduction, then the full recipe). Maximum five hypotheses; after five: restore the snapshot if things got worse, re-read the SPEC FILE, optionally open a HELPER ticket on another provider, then simplify to the smallest version that works and add pieces back one at a time.

Rules that catch most real incidents: never run the same failing check twice hoping for a different result (that is the loop the hook detects); change one thing at a time; **never weaken the WAF, auth, CSRF or validation to pass** — bisect the payload and fix the request; a check that was green and is now red is a regression and jumps the queue; "200 but wrong behaviour" is a logic bug in the agent's own code, not the tool; and if the agent can explain *why* the code behaves as it does but not what the *correct* behaviour is, that is a missing business rule → stop and ask.

The symptom table in §8 of the global context (blank PHP page → `php -l` + `php-fpm` log; 404 on assets → absolute URL; login "works" but logged out → session write/read; form submits, nothing saved → `name=` mismatch; POST returns 403/406 while the page loads → WAF rule, bisect the payload) is the first thing to teach a trainee who will read transcripts: most "stuck" runs are one of these.

### 5.7 When the agent stops to ask — and how you answer

The agent asks only for business rules (P3), destructive actions (H7), missing credentials, or the "should I create the tickets?" gate in PLAN MODE. The format is fixed (global §4.1): one to three lines of what it understood and decided, then numbered questions with options and a recommendation, answerable as "1A, 2B, 3 yes". Before asking you, it should have filtered the questions through a HELPER ticket on another provider (P4) and told you in one line what the helper settled.

Your side of the protocol:

1. Read the ticket's last message in the Ticket Detail page (or the Telegram notification).
2. Answer **every** numbered question in one reply, in the same numbering. Do not answer technical questions the agent should have decided itself — tell it to decide ("2: your call, record it in the SPEC FILE").
3. If the question is a business rule you do not know, get it from the client and record it in the specification's Decision Log too; the package is the source of truth, not the chat.
4. Send. The ticket reopens; the agent writes the answer into the SPEC FILE and stores lasting rules in the knowledge base; it must never ask an answered question again.

If the same question keeps coming back across tickets, the answer is not on disk: check the knowledge base and the project description, and fix that rather than answering again.

### 5.8 The report: two lines, then four parts

Every finished ticket ends with a report written for **you** and read by the auto-reviewer. It starts with two lines in English:

- `NEEDS THE USER: yes — <what>` or `NEEDS THE USER: no` — *yes* means the next tickets must wait for you: a critical question, a destructive-action doubt, an approval, a failed or blocked part that later tickets build on.
- `OPEN ISSUES AND DOUBTS: <numbered list>` or `none` — a part that failed, could not be verified, is blocked, or a result the agent is not sure of. Never hidden to get closed (that is faking a check), never invented (empty hedging holds the plan for nothing).

Then four parts, in this order:

1. **What works now** — with the evidence (which test ran, which URL loaded, which screenshot).
2. **What is waiting for the user** — blocked parts with the exact ask (credentials, decisions), one consolidated ask per service.
3. **What was decided on your behalf** — technical choices worth knowing plus every SAFE DEFAULT, each reversible with one line.
4. **What stays open** — known limits, deferred parts, what the next ticket must know.

Part 3 is where you spend your attention: each safe default is a business assumption you can overturn with one sentence. Part 2 tells you what to chase from the client. A report without evidence in part 1 is a report to distrust — check the SPEC FILE acceptance list and the screenshot. A report that ends with a polite question ("Should I also…?") means the agent needs you — the guides forbid it precisely because it stops the plan.

### 5.9 Verification and the repair loop — one verifier owns the episode

1. **[VERIFY] ticket** (different provider family, `master`, `ultra`, `parent_sequence`/`parent_ticket_id` = the builder; `guides/verify-fix.md` pre-loaded): walks the parent's acceptance list, runs the recipe and `bash .tests/run.sh`, writes its own negative tests, writes only its own SPEC FILE and test files. Findings are numbered with steps, expected and observed; style preferences are not findings. A group verify names several parents (one ticket after the last of them).
2. **No findings** → `VERIFY: PASS · cycle 1` on the parent's SPEC FILE, report `NEEDS THE USER: no`. The reviewer closes it; the plan goes on.
3. **Findings** → the verifier creates ONE `[FIX] <parent title> (#<parent id>, cycle 1)` per parent with findings — the original builder's provider and role, **at the verifier's own `sequence_order`, with no `depends_on`** — writes `VERIFY: FAIL · cycle 1 · … · fix #<id>` on the parent's SPEC FILE, and **parks**: `⏸ WAITING-FOR-TICKET #<fix id>`. A parked verifier keeps its sequence unfinished, so the fix runs at once and everything behind waits.
4. **The fix** fixes only the listed findings, each with a repeatable test that fails before and passes after; a finding it disagrees with is `DISPUTED` with a proof. When done it writes `FIX: done · cycle 1` on the parent's SPEC FILE and **replies to the verifier** (`codehero_update_ticket(ticket_id=<verifier>, reply="FIX done — cycle 1 — fix #<id>")`) — the reply wakes the verifier. It never creates a verify ticket.
5. **The verifier wakes** (cycle 2), re-checks only the findings (plus the acceptance items they touch and the test suite), and either writes `VERIFY: PASS · cycle 2` and reports, or opens cycle 2's fix and parks again.
6. **Circuit breaker**: the same part failed three cycles, the same acceptance item failed twice in a row, or builder and verifier disagreed twice on a finding → the verifier stops, writes `CIRCUIT BREAKER` on the record, reports `NEEDS THE USER: yes` with both views, and stays open until you decide (your decision is recorded as `USER DECISION` and a fresh count starts).

The cycle record lives on disk in the parent's SPEC FILE (`VERIFY:` / `FIX:` lines, append-only; the last `VERIFY:` line decides), because every fix is a new agent with an empty memory and the verifier itself may be restarted. When you see a `[FIX]` appear at the verifier's sequence, do nothing; it is the loop working. When you see the same part fail a third time, expect the breaker and prepare to arbitrate.

### 5.10 Helper tickets and the walkie-talkie

Any ticket may open a `[HELPER]` on another provider when it is truly stuck (step 8 of debugging), when two approaches failed and it cannot choose, when one design decision blocks everything behind it, or when questions are about to go to the user (the AI-before-human filter). Rules (`guides/helper.md`): helpers never write files and never create tickets; the ticket that opens a helper closes it (`status="closed"`) before its own TASK COMPLETED; at most two open at once, on different providers; three exchanges without agreement → both views go to you. A helper can *find* an answer that exists in the material and *judge* a technical trade-off; it can never *invent* a business fact.

The messaging protocol is simple and the platform does the delivery. `codehero_update_ticket(ticket_id=<other numeric id>, reply="...")` sends; the platform signs it (`📨 FROM TICKET #<id> (<number> · <title>)`), so a message without a signature is from a human. A working ticket receives it at its next step — through its own mid-run check, inside the next MCP tool result, or (Claude CLI modes) through a PostToolUse hook — within seconds. A parked ticket (`⏸ WAITING-FOR-TICKET #<id>`, several ids allowed: the first reply wakes it, it parks again for the rest) is woken by the reply. A ticket that ends its turn with a message still unread is re-opened at once by the daemon. A parked ticket whose awaited ticket(s) ended without replying is woken by a watchdog with a `📨 SYSTEM` note, so nothing waits forever.

In the ticket list this looks like: a build ticket in progress, a `[HELPER]` or `[PEER]` ticket on another provider with the same sequence number, the two exchanging numbered findings, then the helper closed by its initiator before the initiator says TASK COMPLETED. An open helper left behind after its initiator finished is the initiator's mistake — and it holds every later sequence.

### 5.11 The replan ticket

The `[REPLAN]` ticket ends every phase of a real project. It builds nothing: it reads the baseline plus the change ledger (`.specs/000-changes.md`), looks at the **real** project (code, `SHOW CREATE TABLE`, the pages on the preview URL, `bash .tests/run.sh`) rather than at reports, and writes a comparison table both ways — every due requirement → where it lives and what proves it; everything built → which requirement asked for it — with `aligned` / `missing` / `wrong` / `not asked for` / `unknown` / `not yet due`. Then one of four decisions: `ALIGNED` → plan the next phase (same rules: contracts, value order, dry run, about ten review rounds, peer check); `REPAIR NEEDED` → a phase of repair tickets (+ their `[VERIFY]`) ending with a new `[REPLAN]`, no new features until a replan says aligned, and a circuit breaker after three repair rounds on the same requirement; `NEEDS THE USER` → one batch of questions and stop; `BLOCKED` → say what is missing. It never edits the baseline to match the code. It does not ask for approval again — the approved plan contained it — unless the scope must change. The last replan of a project is the final check.

### 5.12 Operator's controls

| Control | Where | Effect |
|---|---|---|
| Send Message | Ticket Detail → message box, or Telegram | Reopens the ticket (if awaiting) and continues the same conversation |
| Stop (kill switch) | Stop button or `/stop` | Pauses immediately; ticket parks in `awaiting_input` (reason *stopped*) and waits for your correction |
| Retry / Reopen | Ticket actions | Returns a failed or finished ticket to `open` |
| Start now / Force next | Ticket actions or `codehero_start_ticket` | Forced start: runs the ticket NOW on an extra slot, ignoring its sequence, dependencies, parent and the slot limit; the flag stays (an observer ticket restarts after every reply) |
| Skip | Ticket actions | Marks it `skipped` — satisfies dependencies |
| Close | Ticket actions or `codehero_update_ticket(status="closed")` | Sets it to `done` (there is no separate closed status) |
| Change role / provider / think mode | Ticket edit or `codehero_update_ticket` | Applies to the next run |
| Restore a snapshot | Git Manager / Backup | Rolls the project files back |
| Permission banner | Ticket Detail (semi-autonomous / supervised) | Allow, Deny, or "Approve all similar" |

### 5.13 Reading a run like an operator — a checklist

For every finished ticket:

- [ ] The report starts with `NEEDS THE USER:` and `OPEN ISSUES AND DOUBTS:`, has the four parts, and part 1 cites evidence you can open (a screenshot, a URL, a test name).
- [ ] The SPEC FILE's ACCEPTANCE list is walked; every item is pass or BLOCKED with a reason; nothing was deleted to look green.
- [ ] `.specs/` STATUS shows the final position; `NEXT:` is empty or points at the next ticket.
- [ ] The knowledge graph gained the decisions and dead ends the ticket mentions.
- [ ] No helper or peer ticket was left open.
- [ ] The snapshot of the final state exists (`backup_log`).
- [ ] If the ticket asked something: the question is a business rule, not a technical choice; it came in one batch; a helper filtered it first.
- [ ] If a VERIFY ticket produced findings: exactly one `[FIX]` per parent exists at the verifier's sequence, the verifier is parked on it, and no later sequence started.

### Exercises — Module 5

1. Create a throwaway project by hand (a project and one build ticket: one PHP page with a form that stores a row). Run it in **supervised** mode and approve each call. Write down every tool the agent used and which layer of the context told it to use that tool.
2. Run the same ticket in **autonomous** mode. Compare the transcript: find the SPEC FILE creation, the snapshot calls, the verification recipe, the knowledge store, the 4-part report. Mark any step it skipped and cite the global section it violated.
3. Deliberately create a ticket whose description omits a business rule (e.g., "apply the discount" without saying how). Observe the stop-and-ask. Answer it in the "1A, 2B" format and watch the reopen. Then check that the answer landed in the SPEC FILE and the knowledge base.
4. Create a `[VERIFY]` ticket by hand for exercise 1's ticket (different provider, master, ultra, `parent_ticket_id` = that ticket). Read its findings. If it produced a `[FIX]`, check its provider, sequence and the verifier's parking marker against §5.9; watch the verifier wake and re-check.
5. Trigger the loop detector on purpose (a ticket told to "keep running the failing test until it passes" on a test that cannot pass). Find the hook's message in the transcript and the moment the agent changed approach or stopped.
6. Explain to a colleague, using the lifecycle diagram, why a serial plan with one ticket in `awaiting_input` shows all later tickets as "waiting", and why that is correct.

---
# PART VI — CUSTOMIZING THE BRAIN

## Module 6 — Building your own logic with the global context and the project context

### 6.1 The layers, where they live, and who reads them

| Layer | Source file (edit here) | Installed copies | Read by | Scope |
|---|---|---|---|---|
| **Global context core** | `config/global-context.md` | `/opt/codehero/config/global-context.md` (defaults for new projects and the context-defaults API) and `/etc/codehero/global-context.md` (the assistant's copy) | The executing agent, as `=== PROJECT GLOBAL CONTEXT ===` (the project's stored copy) | Every project |
| **Guides** | `config/guides/*.md` | `/opt/codehero/config/guides/` (served by the MCP tool `codehero_get_guide`; never copied per project, so an edit reaches every ticket at its next call) | The executing agent, on demand by trigger; pre-loaded by the daemon for `[PLAN]` `[REPLAN]` `[VERIFY]` `[FIX]` `[HELPER]` `[PEER]` tickets | Every project |
| **Language / project context** | `config/contexts/<stack>.md` | `/opt/codehero/config/contexts/<stack>.md` | The executing agent, as `=== PROJECT CONTEXT ===` | Every project of that stack |
| **Per-project stored copies** | — (DB: `projects.global_context`, `projects.project_context`) | Copied from the two files above at project creation, with `{PROJECTS_PORT}`, `{ADMIN_PORT}` and `{PROJECT_FOLDER}` resolved | The executing agent | This project only |
| **Project description and info** | UI: Project Settings (`projects.description`, `projects.context`) | — | The executing agent (`PROJECT DESCRIPTION`, `PROJECT INFO`) | This project — the right home for the package's Mandate and run settings |
| **Ticket** | UI or MCP (`tickets.description`, `tickets.context`) | — | The executing agent | This task |
| **Knowledge base** | The agents themselves (and you, by telling a ticket or the AI Assistant to "remember" something) | DB graph | Every ticket at start, plus the hint system | This project, evolving |
| **Assistant templates** | `config/assistant-{general,planner,progress,help}.md` | `/etc/codehero/assistant-*.md` | The in-app assistant modes | The assistant, not the tickets |

Three facts decide how a change propagates:

1. **New projects** copy the current files at creation. Existing projects keep their stored copies until you open *Project Settings → Context*, edit, or load the defaults again. This is a feature (a project's rules do not change under a running plan) and a trap (you deploy a fix and old projects do not get it).
2. **`.md` files are read fresh**: the daemon reads the project's stored copy per ticket; the planner reads its template per session; `codehero_get_context_defaults` reads the files per call. No service restart is needed for context changes — only the copy to the installed paths.
3. **Placeholders are resolved on the global context only.** Write `{PROJECTS_PORT}` and `{PROJECT_FOLDER}` there; never a literal port. The per-language files carry no placeholders (they use `{web_path}` only as a name in prose).

Deployment of a context change on a server:

```bash
# global: source → installed defaults AND the daemon/assistant copy
sudo cp /home/claude/codehero/config/global-context.md /opt/codehero/config/global-context.md
sudo cp /home/claude/codehero/config/global-context.md /etc/codehero/global-context.md
# per-language: source → installed defaults
sudo cp /home/claude/codehero/config/contexts/php.md /opt/codehero/config/contexts/php.md
# guides: source → installed (read by codehero_get_guide)
sudo cp /home/claude/codehero/config/guides/*.md /opt/codehero/config/guides/
# assistant templates
sudo cp /home/claude/codehero/config/assistant-planner.md /etc/codehero/assistant-planner.md
```

Installed copies are overwritten by `setup.sh` / `upgrade.sh`; keep your customizations in the source tree (or a fork) and re-apply after upgrades.

### 6.2 Which layer for which rule

| Kind of rule | Put it in | Not in |
|---|---|---|
| The method: how to plan, build, verify, ask, report; hard rules; debugging; knowledge; verification doctrine | Global context | A ticket (it would apply to one task only) |
| Stack idioms: the canonical bootstrap, the one way to do sessions/DB/CSRF/uploads in this language, the "silent mistakes" of the language | Language context | Global (it would bloat every project) |
| Company-wide conventions that apply to every stack (documentation files, naming, accessibility floor, a required `CHANGELOG.md`) | Global context, §11 (code rules) or §13 ("Documentation you maintain") | Language contexts (you would repeat it 16 times) |
| This project's facts: folder map, existing conventions of an imported codebase, test command, "do not touch" list, the client's Mandate and run settings | Project context (stored copy) and project description | Global |
| The client's business rules, formulas, permissions, worked examples | The specification package → project description (Mandate) + knowledge base (`decision` / `spec` nodes) + each ticket's Contracts section | Global or language context (they are not rules of the method) |
| One task's objective, owned files, definition of done | Ticket description | Anywhere else |

A rule in the wrong layer is the most common customization mistake: a client's VAT formula in the global context leaks into every other client's project; a method rule in a ticket is forgotten by the next ticket.

### 6.3 How the global context is written — and why

The current global context (v6.1: a core of about 49 KB plus ten on-demand guides) is written in **simple English so that every model, big or small, can follow it**. Its conventions are not style; they are what makes weak models comply. Keep them when you add or change rules:

| Convention | Why it works |
|---|---|
| A READ-THIS-FIRST section with a **glossary** and the **11 most important rules** | Small models weight the beginning of the prompt most; the glossary defines every capitalized term once |
| **Numbered hard rules** (H1–H10), each one paragraph, each with the failure it prevents | A rule with a number can be cited, checked in a review, and referenced from other sections ("Rule H2") |
| **Sections that work on their own**, cross-referenced by number ("see Section 8") | After compaction the model may only remember a section number; each section must be usable alone |
| **IF … THEN … prose** and "Never / Always" only for hard rules | Conditionals are executed; adjectives ("try to be careful") are ignored |
| **Tables: symptom → most likely cause → first check** | The model matches the symptom it sees and gets a concrete first action |
| **Examples in real values** (`WHERE id=?` vs `WHERE id=$id`; `.specs/001-login-page.md`) | Abstract rules are misapplied; concrete examples are copied correctly |
| **Placeholders** (`{PROJECTS_PORT}`, `{PROJECT_FOLDER}` — the two the platform substitutes; `<web_path>` for values the agent fills in) instead of literal values | A hardcoded port in the context is wrong on the next installation |
| **Tool names matched by suffix**, "a missing lookup tool is not an error" (a missing creation or verification tool is BLOCKED, never skipped) | Runtimes prefix tool names differently; the model must not stop because a name differs |
| **Evidence phrasing** ("Done = a test ran, a page loaded, a row exists") | Defines "done" operationally so it cannot be satisfied by text |
| **Per-language contexts defer to the global** ("loads AFTER the Global Context — all global rules still apply"; "per Global Section 11") | No duplication, no contradiction, smaller prompts |

Size matters. The core is about 49 KB (roughly 12K tokens) and is sent with every ticket; a guide is paid only by the tickets that need it (planning 36 KB, verify-fix 10 KB, the others 2–16 KB). Every paragraph you add to the core is paid on every ticket of every project: a rule for a recognizable situation belongs in a guide, with a trigger row in core Section 2 — never in the core. Run `python3 tests/context/check_global_context.py` after every edit (references, trigger table, tokens, tables).

### 6.4 The rule for changing rules

> **Change a rule only for a failure you observed, and write the failure next to the rule.**

Every hard rule in the global context names the incident it prevents (H2: processes are killed when the turn ends; H3: hand-inserted rows to pass a test; H6: two tickets editing the same file). A rule added "in case" a model might do something has a cost on every ticket and no evidence it helps; and a defensive rule for a hypothetical failure often makes the model over-cautious about the real work. When a trainee proposes a context change, ask for the transcript that shows the failure. No transcript → no change.

The same applies to removing a rule: find the incident it prevents (git history and the CHANGELOG record most of them) before deleting.

### 6.5 Worked customization 1 — a company convention in the global context

*Observed failure:* three projects delivered without any change log; the client's IT could not tell what a ticket had changed.

*Change:* in §13 "Documentation you maintain", add `CHANGELOG.md` to the list, and in §5 step 9 add one line: *"Append one line to `CHANGELOG.md`: ticket number · date · what changed."* Two sentences, in the two sections where the model already looks for documentation duties. Not a new hard rule (a missing changelog is not a safety failure), not a new section.

*Test (§6.9):* a probe project on the weakest active model; after one ticket, `CHANGELOG.md` exists with one line.

### 6.6 Worked customization 2 — a stack variant (Laravel instead of plain PHP)

The PHP context prescribes plain PHP with PDO and a canonical `includes/config.php`. A client's team maintains Laravel projects and wants CodeHero to follow their conventions.

Two ways, and you must know both:

- **Per project (no platform change).** Create the project with a custom project context: call `codehero_get_context_defaults(context_type="php")`, take the returned `project_context`, replace the bootstrap/page-pattern sections with the Laravel equivalents (artisan commands the agent may run, `routes/web.php`, Eloquent + migrations, Blade layouts, `php artisan test`), keep the "silent mistakes" that still apply, and pass the result as `project_context` to `codehero_create_project`. Or paste it into *Project Settings → Context* after creation. Existing projects can be switched the same way.
- **A new stack file for every future project.** Add `config/contexts/laravel.md`. Note that the stack-to-file mapping is code (`context_map` in `scripts/mcp_server.py` and the matching map in `web/app.py`), so a new `tech_stack` value needs a small developer change in both maps plus the UI option; an unmapped stack silently falls back to `php`. Until the map is extended, use the per-project route.

Whichever route, the file must keep the header line that states it loads after the global context and defers to it, and it must not restate global rules (relative paths, security, libraries) — reference "Global Section 11" instead.

### 6.7 Worked customization 3 — the project context of an imported legacy project

An existing PHP application is imported in *extend* mode. Run `codehero_analyze_project` first (it builds the project map). Then write, in the project's stored project context, the facts the analysis cannot infer and the agent must not guess (P10):

```
## This project (imported 2026-09-15, extend mode)
- Framework: none. Front controller public/index.php → app/Router.php. Do not add a second router.
- DB access ONLY through app/Db.php (PDO, already ERRMODE_EXCEPTION). Never create another PDO.
- Sessions are started in app/bootstrap.php; do not call session_start() elsewhere.
- Tests: `vendor/bin/phpunit` (all green at import; a red test is a regression — Rule §8).
- Do NOT edit: vendor/, public/legacy/ (old reports still in use), app/Legacy/*.
- Naming: snake_case for DB, camelCase for PHP, kebab-case for URLs — keep it.
- Known trap: app/Mail.php sends synchronously; new mail goes through the outbox table (see knowledge base: decision "mail-outbox").
```

Store the same facts as knowledge nodes (`component`, `config`, `decision`) so the hint system shows them when the relevant files are edited. The project context tells the agent; the knowledge base reminds it at the moment it matters.

### 6.8 Worked customization 4 — an API-only project

The global verification recipe is browser-centred. For a project of type `app` with no HTML, the `api` context describes the architecture but the agent still needs an explicit verification recipe. Add to the project context:

```
## Verification for this API (replaces the Browser part of Global Section 9)
- Start the service with ProcessManager; health check: HttpRequest GET http://127.0.0.1:{PORT}/health → 200.
- For every endpoint in the SPEC FILE's CONTRACTS: HttpRequest the happy path AND one negative
  (missing auth → 401, invalid body → 422, other user's resource → 403).
- LogTail(path="{app_path}/logs/app.log", since="5m", level="error") must be empty.
- Run the test suite: `npm test` / `pytest` — 0 failures is the acceptance floor.
- Deliveries (webhooks, emails) need proof per Global Section 9.
```

You are not overriding the global; you are doing exactly what the global tells native projects to do in §15 ("replaces the Browser part of Section 9. Everything else still applies").

### 6.9 Worked customization 5 — client business rules

*Wrong:* adding "VAT is 24% and applies to net, rounded half-up" to the global context.

*Right:* the rule lives in the specification's §7 with a worked example; the planner copies the Mandate into the project description; the knowledge-foundation ticket stores it as a `decision` node ("vat-rounding: 24% on net, round half-up to 2 decimals, per R017 example 3"); every ticket that touches money cites R017 in its Contracts section; the VERIFY ticket tests the example values. The agent finds the rule in three places at run time and never has to guess.

### 6.10 Testing a context change — the protocol

1. **Diff and size.** `diff` against the previous version; check the file size change. A change that adds more than a few hundred bytes needs a reason.
2. **Keep the version header.** The global context's first line names its version; bump it and add one line to the note under it saying what changed and which failure it fixes.
3. **Deploy to the installed paths** (§6.1). No restart needed.
4. **Create a throwaway project** so it receives the new stored copy. Check the copy in *Project Settings → Context*; check that placeholders were resolved (the preview URL shows the real port and folder).
5. **Run a probe ticket twice**: once on your strongest provider, once on the weakest model you actually use for `junior_developer`. The rule must survive the weak one; if only the strong model follows it, rewrite it (shorter, IF/THEN, an example in real values).
6. **Read the assembled prompt** the agent actually received: the daemon writes it to `<work_path>/.heroagent/context_<ticket_id>.tmp` for the run. Confirm your text is there, in the section you expected, once.
7. **Read the transcript** for the behaviour, not the words: did the agent *do* the thing (the file exists, the check ran), or did it *say* it would?
8. **Roll out** to existing projects only where wanted: open each project's Context settings and load the defaults or paste the new text. Running plans keep their old copy until you do.
9. **Record** the change in the repository's CHANGELOG with the incident it fixes.

### 6.11 Anti-patterns (each one seen in a real run)

| Anti-pattern | What happens | Fix |
|---|---|---|
| Contradicting a hard rule from a lower layer ("in this project, you may use `git` directly") | The model follows whichever it read last, unpredictably | Never contradict H1–H8; change the global if the rule is wrong for everyone |
| Literal port or IP in a context (`https://127.0.0.1:9867/…`, `10.0.3.5`) | Wrong on the next installation; container agents try to reach the IP | Placeholders in the global; `localhost:<port>` from the services block |
| The word "container" in a ticket or project context | The agent starts running `lxc`/`docker` commands and breaks | Describe services at `localhost`; the platform routes commands |
| A rule with no example ("use good security practices") | Ignored by small models, over-interpreted by large ones | One concrete example in real values, one negative example |
| A preventive rule for a failure nobody observed | Costs tokens on every ticket; often makes the agent hesitant on the real work | §6.4: no transcript, no rule |
| Duplicating global rules in a language context | Drift: the two copies diverge after the next global edit | Cross-reference by section number |
| `think_mode: ultra` as a project default | Every trivial ticket burns the maximum thinking budget | `balanced` default; `ultra` per ticket for verify/peer/helper |
| Referencing a tool that does not exist in this runtime (`Screenshot` as a built-in) | The model stops or invents | Use the MCP tool names; the global already says "match by suffix; a missing tool is not an error" |
| Business rules in the global context | They leak into every other client's project | Specification → project description + knowledge base |
| A ticket that says "as we discussed" | The executing agent was not in the discussion | Self-contained ticket (Module 4 §4.8) |

### 6.12 Customizing the planner and the assistants

The same discipline applies to `config/assistant-planner.md` and the other assistant templates: they are read per session, they are concatenated with the global context (except `help`), and they carry hard rules at the top. Typical legitimate customizations: a company default strategy (`eco`), a house rule for provider families in verification, extra preview columns, a different default execution mode for a training installation. Illegitimate: removing the preview-and-confirm gate, allowing inactive providers, making parallel the default. Each of those undoes a principle of Module 1.

### Exercises — Module 6

1. Take the customization of §6.5 and apply it to your training installation following the §6.10 protocol end to end. Attach: the diff, the assembled prompt excerpt, the transcript line where the agent writes `CHANGELOG.md`.
2. Write a per-project context for a Node/Express project that must use an existing company middleware package for auth. Show which global sections you cross-reference instead of restating.
3. Find, in your training installation's projects, one project whose stored global context is older than the current file. Explain how you know, and update it without disturbing a running ticket.
4. A trainee proposes adding "Always double-check your work before finishing" to the global context. Argue for or against using §6.3 and §6.4, then propose a version that would actually change behaviour (hint: it already exists — find it).
5. Write a rule for the global context that would have prevented this observed failure: *"The agent reported an email as sent; the SMTP credentials were placeholders; nothing was sent."* Then find the sentence in the v6.1 core that already covers it and compare wording.

---
# PART VII — REACHING A WORKING RESULT

## Module 7 — Delivery discipline: from the first ticket to a verified, documented product

### 7.1 What "working result" means in ADF

Not "the code is written". A working result is: the agreed scope runs on the preview URL (and later on the production domain), every acceptance criterion has evidence linked to it, every business rule was confirmed by the client and is stored where the next ticket finds it, the blocked parts are listed with their exact asks, and the documentation the client agreed to exists in their language. The framework gets you there by ordering the work so that the riskiest unknowns are resolved first and the evidence accumulates as you go.

### 7.2 The opening sequence: probe → knowledge → access gate → core slice

| Ticket | Purpose | Proof it produces |
|---|---|---|
| **Capability probe** (#0) | Verify what this installation can actually do: runtimes and versions, DB access, the preview URL, the services block, build tooling declared in the environment block | A SPEC FILE with one line per capability: available / missing. Missing runtime → the run stops with the fallback question (Module 3 §3.9) |
| **Knowledge foundation** (#1) | Fill the knowledge base with the architecture, the stack, conventions and every key decision from the package, so the graph describes the project from day one | `codehero_knowledge_list` shows the decisions; later tickets find them at step 2 of the work loop |
| **Application setup** | Folders, config bootstrap, schema, seed, shared header/footer; in a container: verify the provisioned services and configure the application-level pieces | Schema applied, seed rows counted, skeleton page loads with 0 errors |
| **Access gate** | The thinnest slice through the real path: login → one protected page → on the preview URL (and, for production deliveries, through the real domain/proxy once it exists) | Screenshot of the logged-in page; `PageAssert` green; logs clean |
| **Core slice** | The product's purpose end to end (e-shop: product page → cart → checkout; RepairFlow: create job → change status → deliver) | The acceptance scenarios of the main process pass, with negative tests from the VERIFY ticket |

Only after the core slice is verified do secondary features start (wishlists, branding, dark theme, extra reports). If a client pushes for the logo first, show them this table: the logo cannot fail; the checkout can.

### 7.3 Milestones and the replan cadence

The Spec Builder sizes the project and sets the cadence (Planning Guide §7.1): S (10–25 tickets, replan after each milestone), M (25–80), L (80–250, batches of about ten). CodeHero executes phase by phase: the planning ticket creates the first phase (about ten tickets), and the `[REPLAN]` ticket that ends each phase plans the next. Early tickets change what late tickets need; a fifty-ticket plan created up front is a plan that will be wrong by ticket twenty.

Revalidation follows the same cadence: one revalidation per milestone for S; after each contract and each functional piece for M and L, plus a final full revalidation for L.

### 7.4 Contracts before code

Two tickets that each "decide" a shared thing will decide it differently (`guides/planning.md` step 5: shared contracts are written before the tickets that consume them). Before any ticket that consumes another's output is created, the shared contract — schema, endpoint, field names, response shape, formula — is written into both SPEC FILES and the knowledge base, and repeated in each ticket's Contracts section. The Planning Guide's chain is *contract → revalidate → module*: a contract ticket writes it, a revalidation checks it, the modules build against it. A changed contract makes the affected evidence stale; the tests are re-run.

### 7.5 Evidence and the acceptance manifest

Every acceptance criterion in the package ends with evidence: requirement version, code revision, test ID, environment. The Evidence column of the requirements register is filled **only** from real test output — never from a ticket's prose. In CodeHero terms: the VERIFY ticket's report, the screenshots (`codehero_screenshot`), the `PageAssert` results and the test-runner output are the evidence; the SPEC FILE's ACCEPTANCE list is where the agent records pass / fail / BLOCKED per item.

Two honesty rules the trainer must insist on: a BLOCKED item is visible and never counted as pass; a passive security scan's clean result records what was scanned, not "no problems exist".

### 7.6 Day-0, touchpoints, and how to keep the client out of the build loop

Before the run: collect the day-0 pack (Module 2 §2.12). During the run: the client is contacted only for the four reasons. Everything else is your job as operator: answer technical questions the agent should have decided (tell it to decide), chase the client only for genuine business decisions, and keep the specification's Decision Log in sync with every answer you relay. A run that stops daily with business questions has an incomplete specification; a run that stops daily with technical questions has a context problem (Module 6); a run that never stops but delivers wrong behaviour has a verification problem (Module 5 §5.9).

### 7.7 Circuit breakers — when the framework stops itself

| Breaker | Trigger | What you do |
|---|---|---|
| Verify/fix loop | Same part failed three fix→verify cycles; same acceptance item failed twice; builder and verifier disagreed twice | Read both views (the verifier's record lines and the fix ticket); decide; reply to the parked verifier with the decision |
| Replan repair loop | The same requirement still not aligned after three repair rounds | Read the replan's comparison table and the repair tickets; decide whether the baseline or the code is wrong; reply to the replan |
| Debugging | Five failed hypotheses (after a helper was consulted) | Read the SPEC FILE's hypotheses; often the missing piece is a business rule, not a bug |
| Loop detector | Identical actions repeated | The hook already nudged the agent; if it hard-stopped, read the last tool calls, fix the ticket text or the environment, retry |
| Helper dialogue | Three exchanges without agreement | Both views come to you; arbitrate |
| Fallback | Ticket #0 cannot provide the runtime | The fallback changes an agreed capability → requirements change with the client, one line per affected requirement |
| Watchdog | Long unproductive run | Ticket marked `stuck`; read, correct, retry |

The breakers are not failures of the framework; they are the framework refusing to burn money on a problem that needs a human.

### 7.8 Documentation deliverables

Always, in the client's language: a user manual per role, an administrator guide, an operations/hosting guide (install, upgrade, backup, restore, monitoring), API documentation when an API exists, and a *Decisions* document listing everything decided for the client. Inside the project the agent also maintains `technologies.md`, `map.md` and the `.specs/` files. Plan documentation tickets as `junior_developer` / `basic` near the end of each milestone, not as an afterthought at the end of the project.

### 7.9 From preview to production

The preview URL is where the agents work. Going live is an operator task, done with the platform's tools and documented in the User Guide:

| Step | Where | Notes |
|---|---|---|
| Domain and SSL | Project → Production Deployment; Settings → Domains | Let's Encrypt or custom certificates; the production config is generated per project |
| Web application firewall | WAF setup (see the WAF guide) | Keep it on; the agents are trained to bisect payloads, never to weaken it |
| Backups and restore drill | Project → Backup & Restore; container snapshots | The specification asked for a restore drill executed once — do it before go-live, not after |
| PHP settings | Project → PHP Settings | Development tuning (errors visible, opcache revalidate) vs production values |
| Secrets | `.env` in the project root, never in code | Real SMTP, payment and API credentials replace the day-0 placeholders here |
| Security gate | The package's automated security tests + the external pentest item | The external pentest is tracked as `external-pending`; it blocks go-live sign-off only if the client's policy requires it |

### 7.10 The operator's daily checklist

- [ ] Tickets in `awaiting_input`: reason? question → answer in one batch; permission → allow/deny; completed (strict) → review the report and close; stopped → correct and retry.
- [ ] Tickets in `failed` past retries or `stuck`: read the last messages, fix the cause (ticket text, environment, credentials), retry.
- [ ] Helpers and peers left open by finished tickets: close and note.
- [ ] New fix tickets: expected; third fix ticket for the same part: prepare to arbitrate.
- [ ] The replan ticket of the phase: read its plan before it runs if you want scope changes.
- [ ] Knowledge base growth: decisions and dead ends are being stored (a flat graph after many tickets = context problem).
- [ ] Snapshots exist for each finished ticket; the latest restores cleanly (test it once per milestone).
- [ ] Day-0 items still missing: chase the client; BLOCKED items depend on them.

### 7.11 A catalogue of real failure patterns and what they mean

Every item below happened in a real run. Learn to recognize them from the transcript.

| What you see | What it means | Where the fix belongs |
|---|---|---|
| The agent claims a page works; the screenshot shows a 500 | A tool hid the error (blank body, stale log); the agent trusted text | Verification recipe (`LogTail`, `php -l`); newer tool versions surface the error automatically |
| The agent "forgot" the plan mid-ticket and rebuilt something | Context compaction without a current SPEC FILE, or a model window smaller than the configured limit (silent truncation) | Check the provider's real context window vs the configured limit; enforce §6 (SPEC FILE current after every part) |
| Ticket ends its turn "to wait for the build" and everything dies | H2: processes are killed at turn end; `run_in_background` is now denied by the hook | Ticket text should not ask for background runs; ProcessManager for services |
| A ticket asks "which framework should I use?" | Type-1 technical question the agent should decide | Answer "your call, record it"; if frequent, the context is unclear about the default stack |
| Two parallel tickets both edited `header.php` | Parallel approved without the ownership analysis, or ownership lists missing from the descriptions | Serialize; H6; ownership table in the plan |
| Ticket text mentions `codehero-12` or `10.0.3.x` | Infrastructure leaked into the ticket | Rewrite with `localhost`; never the word "container" |
| The verifier "fixed" the code | The ticket title lost its `[VERIFY]` prefix, so the verify-fix guide was not pre-loaded | Keep the prefix; the guide says "you only CHECK" |
| A finished helper ticket still `open` | Initiator forgot to close it | Close; it is in the initiator's checklist |
| A ticket stays `awaiting_input` for days and nothing behind it moves | It asked you something (`NEEDS THE USER: yes`) or waits for another ticket; a later sequence never starts until it is done | Daily checklist; answer in one batch, or close it |
| Every ticket burns the maximum thinking budget | `ultra` set as project default | `balanced` default; `ultra` per ticket |
| Weak model loops on an easy PHP task | Tools hid a PHP 500; loop detector saw A/B alternation | Verification recipe first; the hook now catches cycles, not only identical repeats |
| Reviewer closed a ticket that actually asked a question | Strict/relaxed confusion, or the question was buried under "TASK COMPLETED" | The reviewer now treats a flagged problem as ERROR; teach the agent's ask format (question first, marker last) |

### Exercises — Module 7

1. Take the RepairFlow plan of Module 4. For each of the first five tickets write the *proof it produces* (a sentence naming the artefact you would open to check it).
2. Write the day-0 pack for RepairFlow in the client's language, and the four-reason contact list as you would send it to the owner.
3. Simulate a breaker: a VERIFY ticket reports "deadline computed as +15 days", the fix ticket replies "the spec says 14 business days" (DISPUTED), the verifier re-checks and disagrees again. Write the message you send to the parked verifier, and the line you add to the Decision Log.
4. Plan the documentation tickets for RepairFlow phase 2 (roles, think modes, sequence, dependencies).
5. Pick three rows of the failure catalogue and find the exact sentence in the global context (or the planner) that exists because of them.

---

# PART VIII — CAPSTONE

## Module 8 — The capstone project and the assessment

### 8.1 The assignment

In pairs (one plays the client, one the developer; then swap), deliver a small internal tool end to end within one working day:

1. **Interview** the client with the Spec Builder (Module 2). Deliver a *Ready to build* package with at most one non-critical *Assumed* item. The tool must have: two roles, one entity with at least three states and history, one business rule with a number (a deadline, a limit or a formula), one notification, one export or printout.
2. **Justify the stack** (Module 3): the one-line decision, the environment block, and the answer to "why not a container?" (or "why a container?").
3. **Plan** it in IMPORT MODE (Module 4). Before confirming, produce a written review of the preview: three changes you made and why.
4. **Run** phase 1 (Module 5) in relaxed autonomous mode. Answer every question the run raises within the "1A, 2B" format. Keep the Decision Log in sync.
5. **Customize** one thing (Module 6) that the run showed was needed — with the transcript that proves the need, the diff, the §6.10 test.
6. **Deliver** (Module 7): the core slice verified on the preview URL by a VERIFY ticket on a different provider family; the 4-part handoff for the client; the documentation tickets planned; the day-0 items listed.

### 8.2 The rubric

| Area | Pass | Distinction |
|---|---|---|
| Interview | Every stage covered or consciously defaulted; four statuses used; critical items never *Assumed*; Stage P preview done | Client's own numbers appear in every business rule's example; dependency register has verification statuses; spreadsheet intake applied |
| Stack | Correct default (PHP/MySQL unless a trigger fires); justification cites a requirement ID | Fallback stack reasoning correct; build vs runtime vs serving declared separately |
| Plan | Serial, probe → knowledge → setup → access gate → core slice; VERIFY tickets on a different family with master+ultra; descriptions follow the five-part recipe | A parallel group offered *and* correctly analysed, or correctly refused with the ownership reason |
| Run | Every question answered in one batch; no technical question answered by the human; helpers closed; snapshots exist | A breaker occurred and was arbitrated correctly; a safe default was overturned via the report's part 3 |
| Customization | Observed failure → rule → deployed → tested on a weak model → transcript proves behaviour | The rule is in the right layer, cross-references the global, and adds under 300 bytes |
| Delivery | Core slice acceptance list all pass or BLOCKED with reason; 4-part handoff; documentation planned | Restore drill performed; production steps listed; the client can read the handoff without you |

### 8.3 Self-assessment quiz

Answer without looking; then check against the referenced sections.

1. Name the two kinds of unknowns the agent meets, and who decides each. *(Global §4)*
2. What does the agent do when a CRITICAL question has no answer and the run is autonomous? *(Global §4.1, `guides/asking.md`)*
3. Which ticket statuses satisfy a dependency? Does `awaiting_input`? Does `timeout`? *(Module 5 §5.1)*
4. Give the three settings every VERIFY ticket must have, where its fix ticket goes, and one thing it must never do. *(`guides/verify-fix.md`)*
5. What is the shipped default of `MAX_PARALLEL_TICKETS_PER_PROJECT`, and what does that mean for a plan where two tickets share a `sequence_order`? *(Module 4 §4.6)*
6. Why does the Spec Builder never name a provider or a model? *(Planning Guide §1.2, §7.5)*
7. Which four things does the `codehero_environment` block declare separately, and which one alone decides `container_required`? *(Module 3 §3.6)*
8. Where does a client's VAT rule belong, and where does it *not* belong? *(Module 6 §6.2)*
9. What are the four parts of the handoff report, and which part contains the safe defaults? *(Global §5 step 10)*
10. A ticket's last message is `⏸ WAITING-FOR-TICKET #418`. Ticket 418 is still running. What does the auto-reviewer do? *(Module 5 §5.1)*
11. Name three "danger files" the ownership analysis checks by name. *(`guides/planning.md` §2)*
12. Which file does the agent re-read first when it feels lost after compaction? *(Global §6)*
13. What is the difference between a SAFE DEFAULT and a guessed business rule? *(Global §4.1, `guides/asking.md`)*
14. Why must ticket descriptions never contain the word "container"? *(Planner rule 8)*
15. A trainee wants to add a rule "always be careful with money". What do you ask for first? *(Module 6 §6.4)*
16. A build ticket at sequence 3 is left `awaiting_input` by the reviewer. Can a ticket at sequence 4 start? Can a forced ticket at sequence 9? *(Module 4 §4.6)*
17. Which two lines open every agent report, and what does the reviewer do with each? *(Module 5 §5.8)*

### 8.4 Certification checklist

A developer is ready to run client projects unsupervised when they can:

- [ ] run a Spec Builder interview and review its package with the Module 2 checklist;
- [ ] state the stack decision and its justification for any of the eight mini-cases without notes;
- [ ] read a planner preview and find the three most common defects (wrong verify provider, visual work on a text-only provider, missing dependency);
- [ ] answer an agent's question batch correctly (business only, one batch, Decision Log updated);
- [ ] recognize the twelve failure patterns of Module 7 from a transcript;
- [ ] change a context rule following the §6.10 protocol and show the transcript that proves it worked;
- [ ] explain the twelve principles to a client in plain language.

---

# APPENDICES

## Appendix A — Quick reference cards

### A.1 Ticket fields

| Field | Values | Default |
|---|---|---|
| `sequence_order` | integer; unique ascending = serial; same = parallel group | required |
| `depends_on` | bulk call: 1-indexed positions of the same call, earlier only · single create: existing ticket ids or ticket numbers | none |
| `parent_sequence` / `parent_ticket_id` | earlier position / existing ticket id | none |
| `ai_model` | `master_developer` · `senior_developer` · `junior_developer` | project default |
| `provider` | an *active* provider | project default |
| `think_mode` | `off` · `basic` · `balanced` · `ultra` | project default (`balanced`) |
| `execution_mode` | `autonomous` · `semi-autonomous` · `supervised` | project default (`autonomous`) |
| `deps_include_awaiting` | `1` relaxed (the auto-reviewer closes clean tickets) · `0` strict (you close each) | `1` |
| `ticket_type` | feature · task · bug · debug · rnd · improvement · docs | feature |
| `priority` | low · medium · high · critical | medium |
| `is_forced` | `1` = forced start (Start Now / Force Next / `codehero_start_ticket`): starts now, ignores sequence, dependencies, parent and slots | `0` |

### A.2 Ticket statuses

`open` (eligible) · `in_progress` (agent running) · `awaiting_input` (parked: completed / question / error / permission / stopped / deps_ready) · `done` (also what "close" means — there is no `closed` status) · `failed` (retries exhausted) · `stuck` (watchdog) · `timeout` · `skipped` (counts as complete) · `new` / `pending` (rare). A higher sequence starts only when every lower one is `done` or `skipped`.

### A.3 Roles and think modes per ticket type (Spec Builder table)

| Ticket type | role | think_mode |
|---|---|---|
| Planning, replan, contracts, architecture, security | master_developer | ultra |
| Verification / peer review / helper / replan | master_developer (different provider for verify, peer and helper) | ultra |
| Feature implementation | senior_developer | balanced |
| Repetitive work, docs formatting | junior_developer | basic |
| Tests and fixtures | senior_developer | balanced |

### A.4 The agent's tools

Built-in: `Read` `Write` `Edit` `MultiEdit` `Glob` `Grep` `Bash` `ProcessManager` `HttpRequest` `Browser` `PageAssert` `LogTail` `WebFetch` `GetCached`.
Platform (MCP): `codehero_knowledge_search/store/list/delete` · `codehero_git_operations` · `codehero_screenshot` · `codehero_extract_context` · `codehero_get_guide` · `codehero_get_ticket` `update_ticket` (reply, status) `create_ticket` `list_tickets` `bulk_create_tickets` `get_project_progress` `start_ticket` · `codehero_get_project` `get_providers_info` · `codehero_container_operations` · `codehero_codebase_status`.

### A.5 The global context, by section

**Core:** 0 Read this first (glossary, 11 rules) · 1 Language rule · 2 Guides: the trigger table · 3 Hard rules H1–H10 · 4 Decide alone vs ask (4.1 asking, safe defaults, blocked) · 5 The work loop (+ the light loop for a small change) · 6 The SPEC FILE · 7 Knowledge base · 8 When something fails · 9 Verification (9.1 nothing internal downloadable, 9.2 repeatable tests) · 10 Git backup · 11 Code rules · 12 Messages between tickets · 13 Environment & paths · 14 Final checklist. **Guides:** planning · verify-fix · asking · helper · debugging · frontend · database · build · testing · native.

### A.6 Walkie-talkie

Send: `codehero_update_ticket(ticket_id=<other numeric id>, reply="...")` — the platform signs it `📨 FROM TICKET #<id>`. Receive while running: `📨 INCOMING MESSAGE` at the next step (own check, MCP result, or CLI hook). Park: end the turn with `⏸ WAITING-FOR-TICKET #<id>[, #<id>] — its reply will wake me` + `TASK COMPLETED`; a reply wakes you; an awaited ticket that ends without replying triggers a `📨 SYSTEM` wake-up. Ended with a message unread → re-opened at once. Close a helper you opened: `codehero_update_ticket(ticket_id=<helper>, status="closed")`.

## Appendix B — File map

| Purpose | Path |
|---|---|
| Global context (source / installed defaults / daemon+assistant copy) | `config/global-context.md` / `/opt/codehero/config/global-context.md` / `/etc/codehero/global-context.md` |
| Language contexts | `config/contexts/*.md` → `/opt/codehero/config/contexts/` |
| Guides (on demand, `codehero_get_guide`) | `config/guides/*.md` → `/opt/codehero/config/guides/` |
| Repeatable-test runner (installed as `.tests/run.sh` in every project) | `libs/tests/run.sh` → `/opt/codehero/libs/tests/run.sh` |
| Walkie-talkie hook (Claude CLI modes) · context refresh | `scripts/message_hook.py` · `scripts/refresh_global_context.py` |
| Context checkers | `tests/context/check_global_context.py` · `tests/context/check_test_runner.py` |
| Spec Builder knowledge file | `docs/CODEHERO_PLANNING_GUIDE.md` (served at `/docs/CODEHERO_PLANNING_GUIDE.md`) |
| Assistant templates | `config/assistant-*.md` → `/etc/codehero/assistant-*.md` |
| Provider ↔ role model map, think budgets, sub-agent roles | `heroagent/heroagent.conf` (synced to `/opt/codehero/heroagent/` and `/etc/codehero/`) |
| Provider API keys | `/etc/codehero/api_keys.conf` |
| System settings (ports, parallelism, cooldowns, context thresholds) | `/etc/codehero/system.conf` |
| Daemon / MCP server / permission hook | `scripts/claude-daemon.py` · `scripts/mcp_server.py` · `scripts/permission_hook.py` |
| Agent and tools | `heroagent/heroagent.py` · `heroagent/tools/` · `heroagent/providers/` |
| Per-ticket assembled prompt and conversation | `<work_path>/.heroagent/context_<ticket>.tmp` · `<work_path>/.heroagent/conversation_<ticket>.json` |
| Project SPEC FILES and docs | `<work_path>/.specs/*.md` · `technologies.md` · `map.md` |
| Web projects / app projects | `/var/www/projects/<slug>` · `/opt/apps/<slug>` |
| Local libraries | `/opt/codehero/libs/` |
| Logs | `journalctl -u codehero-daemon` · `/var/log/codehero/daemon.log` · `/var/log/codehero/web.log` |

## Appendix C — Reading list (in order)

1. `config/global-context.md` — read it twice; it is the framework. Then `config/guides/planning.md`, `verify-fix.md`, `helper.md`, `asking.md` — the situations.
2. `docs/CODEHERO_PLANNING_GUIDE.md` — Parts 1, 2, 3 and 7 first; Parts 4–6 as reference.
3. `config/assistant-planner.md` — short; read it before your first import.
4. `config/contexts/php.md` — the reference language context; then the context of your stack.
5. User Guide chapters 8 (Execution Modes), 9 (Sequencing), 11 (Lifecycle), 13–16 (providers, roles, think mode, vision), 31 (Containers), 32 (Production).
6. `docs/SMARTCONTEXT.md` — how compaction works and why the SPEC FILE exists.
7. `CHANGELOG.md` — the incident history behind the rules.
8. The presentation [*The Domain Expert's Software Factory*](presentations/domain-experts.html) — the same method told to the client's side; useful before Module 2's interview exercise.

---

*CodeHero Developer Training v1.1 — for CodeHero PRO 4.49+ (Global Context v6.1). The framework files cited here are the source of truth; when this course and a framework file disagree, the framework file wins and this course needs an update.*
