diff --git a/README.md b/README.md index bf87693af..6d8a41237 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,8 @@ Deep Dive"> > Looking for Context Engineering? [Jump straight to factor 3](https://github.com/humanlayer/12-factor-agents/blob/main/content/factor-03-own-your-context-window.md) > > Want to contribute to `npx/uvx create-12-factor-agent` - check out [the discussion thread](https://github.com/humanlayer/12-factor-agents/discussions/61) +> +> Want a practical boilerplate to start from? See the [starter template](https://github.com/humanlayer/12-factor-agents/blob/main/content/starter-template.md) diff --git a/content/starter-template.md b/content/starter-template.md new file mode 100644 index 000000000..a71e9ff5c --- /dev/null +++ b/content/starter-template.md @@ -0,0 +1,63 @@ +# Starter Template: Build a 12-Factor Agent + +This page is a practical boilerplate for starting a new 12-factor-style agent project. + +If you want a guided walkthrough, start with: +- [Python workshop walkthrough](https://github.com/humanlayer/12-factor-agents/blob/main/workshops/2025-07-16/walkthrough_python_enhanced.yaml) + +## Suggested project layout + +```text +my-agent/ + README.md + pyproject.toml or package.json + src/ + agent/ + prompts/ + tools/ + workflow/ + reducers/ + context/ + state/ + tests/ +``` + +## Minimal implementation checklist + +1. Define a small set of tool schemas (Factor 4). +2. Put prompts in source control with tests/examples (Factor 2). +3. Build context in code, not hidden framework magic (Factor 3). +4. Keep control flow explicit in deterministic code (Factor 8). +5. Persist execution + business state in one timeline (Factor 5). +6. Treat the agent loop as a reducer over prior events (Factor 12). + +## Copy/paste starter loop (framework-agnostic pseudocode) + +```python +events = load_events(thread_id) + +while True: + prompt = build_prompt(events) + tool_or_reply = llm_call(prompt, tools=tool_schemas) + + if tool_or_reply.type == "final_reply": + events.append({"type": "assistant_reply", "text": tool_or_reply.text}) + break + + result = run_tool(tool_or_reply.name, tool_or_reply.args) + events.append({ + "type": "tool_result", + "tool": tool_or_reply.name, + "args": tool_or_reply.args, + "result": result + }) + +save_events(thread_id, events) +``` + +## "Done enough" criteria for v0 + +- You can replay a thread from stored events and get the same next action. +- All tool calls are schema-validated before execution. +- The agent can be paused and resumed without hidden in-memory state. +- Failures are compacted into context and retried with bounded attempts.