Files
ai-resume/AGENTS.md
Sam Rolfe b267e55f8c Replace Vite/React scaffold with Go build spec
- AGENTS.md: build spec for Paperclip (constraints, conventions, 7 phases)
- docs/phase-1..7: per-phase work, DoD, out-of-scope, risks
- reference/: frozen decisions, stack+ports+budgets, content map, acceptance tests
- agents/: persona and security policy drafts
- Retires the React scaffold; history retained as record of the false start
2026-10-26 16:02:35 +11:00

169 lines
8.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Ai Resume — Build Spec
> Build spec for Paperclip. Follow the phases in section 11 in order. Do not skip a
> phase's Definition of Done. When something is unclear, ask Sam — do not guess.
**Project:** `Resume Ai` (Paperclip project `aeea3686-b9fb-4e20-aaaa-4d970f7aeb64`)
**Repo:** `sam/ai-resume` — this working copy. One repo, one product.
**Planning folder (read-only reference, do not edit):** `/home/sam/paseo/projects/resume_ai_system/`
---
## 1. Purpose and outcome
A public portfolio site for Sam Rolfe, aimed at three roles: **AI / LLM Engineer**, **Platform / DevOps Engineer**, **Edge / IoT Engineer**. It must present 25 years of delivery, a homelab, an edge fleet and an AI estate in a form a hiring manager can judge in 90 seconds and an engineer can verify in 30 minutes.
**The single success statement:**
> A recruiter opens the link, understands within 90 seconds that Sam builds AI systems, the platforms under them and the hardware at the edge — and can drill from any claim to the code, diagram or device that proves it. Separately, they can ask a question in plain English and get a short, honest, cited answer.
If those two things work, the project succeeded. Everything else is polish.
---
## 2. The two-mode rule — non-negotiable
The site has **two delivery modes over one body of content**. Both are mandatory.
**Mode A — prebuilt static content.** Conventional navigation into fixed, pre-rendered pages. No LLM call, no embedding lookup. This is the fallback and the first impression. It must work with every AI service stopped.
**Mode B — AI conversational retrieval.** A prompt box; answers generated from the corpus, streamed; the AI can push artefacts (code, diagrams, images) into the presentation panel.
**One source of truth, two renderers.** `content/` (Markdown + front-matter + assets) is authoritative. A build step emits both (a) the static pages and (b) the chunked, metadata-tagged corpus. Content is never authored twice, and the two modes can never drift.
**Acceptance test A1 *(hard gate)*:** stop Qdrant, OmniRoute and the query service. Every page must still render correctly. Any change that breaks this is rejected.
---
## 3. Scope
**In scope**
- The static site: navigation, six top-level areas, drill-down pages, print/accessible.
- The content pipeline: `content/` → static render + corpus.
- The AI overlay: query graph, retrieval, streaming, citations, guardrails, cost caps.
- Public deployment behind the existing Caddy edge.
- Honest labelling of in-progress and abandoned work.
**Out of scope**
- Changing, stopping or "cleaning up" any other system on any host. See §4.
- Family/household systems, the Hub, Paperclip itself, the model gateway's internals.
- A CMS, admin editor, user accounts, comments, analytics dashboards.
- Native apps, voice *output* beyond the optional last phase.
---
## 4. Hard constraints
1. **Stack is frozen.** Go + `templ` + HTMX + SQLite; one hand-written TypeScript island; Qdrant; Prefect; LangGraph; OmniRoute. React, Vite and `node_modules` do not enter this repo. Reopening a frozen decision requires Sam's written approval, not a judgement call.
2. **Do not touch other systems.** Nothing outside this repo and the deploy path. No stopping containers, no editing other projects' compose files, no changes to Caddy beyond the single block specified in Phase 3, no `nixos-rebuild`. If a task appears to require it, stop and ask.
3. **Memory ceiling.** New footprint ≤ **1.0 GiB** and ≤ **4 containers**. Every new service sets `mem_limit` **and** `memswap_limit` to the same value, so it cannot consume the host's swap.
4. **Secrets** come from `~/.config/environment.d/` only. Never in the repo, never in logs, never echoed. A secret-scanning pre-commit hook is mandatory.
5. **All model calls go through OmniRoute.** No direct provider SDK or HTTP call anywhere in this codebase.
6. **No LLM in the path of a consequential action.** Deployments are executed by a script, not decided by a model.
7. **The public AI has no tools.** No shell, no filesystem, no network fetch, no write path, no memory between visitors. This is architectural, not a prompt instruction.
---
## 5. Where it runs
| Host | Role | Notes |
|---|---|---|
| `.27` | Build / dev | Source, builds, agent work |
| `.13` | Runtime | Go app, Qdrant, Prefect worker. **2.3 GiB free, 8 GiB swap in use — respect the ceiling** |
| `.35` | Public ingress | Caddy terminates 443 for `*.lab.audasmedia.com.au` |
| Item | Value |
|---|---|
| App port | **8096** (verify free; 8095 is taken by `offsite.lab`) |
| Qdrant | 6333 / 6334, bound to `127.0.0.1` |
| Public hostname | `resume.lab.audasmedia.com.au` (wildcard DNS already resolves) |
| Release path | `/home/sam/deployment/resume/releases/<timestamp>` + `current` symlink |
| Edge proxy | Caddy on `.35` — **Sam applies this change, not the agent** |
Bind every new service to `127.0.0.1`. Caddy is the only public listener.
---
## 6. Repository rules
- `main` is always deployable. Work on branches; merge when the phase's DoD passes.
- The repo **is** the content source of truth. `content/` lives here.
- No generated artefacts committed (build output, `node_modules`, `.venv`, binaries).
- Every phase ends with a commit that states which DoD items it satisfies.
- The repo stays **private until Phase 3 passes**, then visibility is Sam's decision.
---
## 7. Content conventions
Every content file carries front-matter. Both renderers read it.
```yaml
id: edge-snapcast
area: ai | platform | edge | products | history | about
level: 1 | 2 | 3
title: "Distributed Audio"
claim: "Eight synchronised endpoints with music ducking for voice."
confidence: delivered | running | in-progress | abandoned | historic
period: "2023–"
tech: [Snapcast, Mopidy, Spotify, Raspberry Pi]
metrics: [{label: "endpoints", value: 8}]
artefacts: [{type: repo|image|video|doc, label: "...", url: "..."}]
public: true
last_verified: 2026-10-20
tags: [audio, snapcast, voice]
```
**`confidence` is displayed on the page.** `running` and `delivered` are claims; `in-progress` and `abandoned` are stated as such. Never promote a value to make a page read better — that is a defect, not a style choice.
**Framing rule:** headings describe capabilities in corporate language. Product names are supporting evidence, never the heading. `ESP32` → *distributed edge computing under power and latency constraints*.
---
## 8. Quality bar
- Renders correctly with JavaScript disabled, except the AI console.
- Lighthouse ≥ 95 performance and ≥ 95 accessibility, mobile and desktop.
- Every page printable.
- Markdown and code highlighting rendered server-side (`goldmark`, `chroma`) — not in the browser.
- No page requires an AI call to be useful.
- Server-rendered HTML validated; no unescaped user input reaches a template.
---
## 9. What is explicitly out of scope for the agent
- Deciding what is true about Sam's career. If the evidence is not in `reference/` or `content/`, ask.
- Naming clients that Sam has not approved.
- Publishing personal details: family, address, phone.
- Changing the stack, the ports, the host allocation or the public hostname.
- Deleting anything outside this repo.
---
## 10. When something is unclear
Ask Sam. Do not guess, do not invent a plausible answer, do not silently choose an alternative. A blocked task that gets answered in a minute is cheaper than a completed task built on an assumption.
Escalate in this order: (1) the phase document, (2) `reference/`, (3) Sam.
---
## 11. Phases
Each phase is one Paperclip issue. Each has a Definition of Done that must be demonstrated with an artifact — command output, screenshot, measurement or URL — not asserted.
| # | Phase | Doc | Depends on |
|---|---|---|---|
| 1 | **Content source of truth** — schema, validator, `content/` populated for all six areas | `docs/phase-1-content-source.md` | — |
| 2 | **Mode A static site** — Go + templ + HTMX, nav, stage panel, drill-downs | `docs/phase-2-static-site.md` | 1 |
| 3 | **Public deployment** — `deploy.sh`, releases, Caddy block, live URL | `docs/phase-3-deploy.md` | 2 |
| 4 | **Corpus and retrieval** — chunk, tag, embed, upsert Qdrant; freshness audit | `docs/phase-4-corpus.md` | 1, 2 |
| 5 | **Mode B console** — SSE, query graph, citations, panel takeover | `docs/phase-5-ai-overlay.md` | 3, 4 |
| 6 | **Guardrails, cost and kill switch** — any-guardrail, persona, caps, red-team | `docs/phase-6-guardrails.md` | 5 |
| 7 | **Polish** — logos, diagrams, code exhibits; optional voice | `docs/phase-7-polish.md` | 3 |
**Phase order is deliberate.** Content first because both renderers depend on it. Deploy at Phase 3, not last, because a live URL that is half-built is worth more than a perfect site that never ships. AI after deployment so it can never block launch.
Reference material: `reference/decisions.md` (why the stack is what it is), `reference/stack.md` (topology, ports, budgets), `reference/content-map.md` (what goes where), `reference/acceptance-tests.md` (the full test list).