Skip to content

Commit a207c66

Browse files
apiadclaude
andcommitted
docs: add AGENTS.md adopting the workspace know-how convention
Repo door for AI coding agents — orientation, layout, conventions, common workflows (test/release/feature), undertested surfaces, and a list of things to NOT do (with the startup-broadcast trap surfaced prominently after a recurring drift). Distinct from the existing AGENT.md (singular), which is Alex's code-agent thinking protocol. This file (plural) is structural and is what Codex/Aider/etc. auto-load. Know-how index left empty — entries get added as recurring procedures emerge. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 04052f4 commit a207c66

1 file changed

Lines changed: 147 additions & 0 deletions

File tree

AGENTS.md

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
# AGENTS.md — violetear
2+
3+
This file is the door for any AI coding agent working in this repo. Read it
4+
first. Other tools (Codex, OpenCode, Cursor, Aider) auto-load it; for Claude
5+
Code it's loaded via the workspace convention in `~/Workspace/CLAUDE.md`.
6+
7+
There is also an `AGENT.md` (singular) — Alex's personal protocol describing
8+
how to *think* before coding (Understand → Plan → Develop → Document). That
9+
file is voice/process; **this file (AGENTS.md, plural) is structural**.
10+
11+
## What violetear is
12+
13+
A full-stack isomorphic Python web framework. FastAPI + uvicorn on the
14+
server; Pyodide bundle on the client. Ships a server-side HTML builder
15+
(`markup.Element`, `HTML.div(...)`), a reactive-state layer (`@app.local` +
16+
`ReactiveProxy`) that emits `data-bind-*` annotations during SSR and
17+
hydrates them on the client, a `DOMElement` wrapper for imperative
18+
browser-side DOM work, a WebSocket RPC bus (`@app.server.rpc` /
19+
`@app.client.realtime`), a CSS DSL (`Style`, `StyleSheet`), and PWA
20+
scaffolding. No JS framework, no templates, no htmx.
21+
22+
Vault node: `vault/Efforts/Repos/violetear.md` (in Alex's workspace).
23+
24+
## Layout
25+
26+
```
27+
violetear/ package source
28+
app.py App, ClientRegistry, ServerRegistry, SocketManager, bundle gen
29+
markup.py Element, Document, HTML builder, Component
30+
state.py @local decorator, ReactiveProxy, LeafProxy
31+
client.py Pyodide-side: ReactiveRegistry, hydrate(), socket listener
32+
dom.py Pyodide-side: DOMElement, DOM static factory, Event protocol
33+
storage.py Pyodide-side: store/session wrappers around localStorage
34+
style.py fluent style builder
35+
stylesheet.py stylesheet builder, selectors
36+
color.py Color class + Colors named-color registry
37+
pwa.py Manifest, ServiceWorker generators
38+
presets.py FlexGrid, SemanticDesign, UtilitySystem, Atomic
39+
tests/ pytest suite
40+
docs/ quarto docs site + example .py files (consumed by test_examples.py)
41+
examples/ hand-written demos (hello_world, reactivity, full_pwa, …)
42+
issues/ design docs for unimplemented features
43+
.github/workflows/ CI (ruff format-check + pytest on push/PR)
44+
roadmap.md v1.0 roadmap (Phases 1-4)
45+
AGENT.md Alex's code-agent thinking protocol (orthogonal to this file)
46+
```
47+
48+
## Conventions
49+
50+
- **Python 3.12+** required. Use modern features: `match`, `list[str]` (not
51+
`typing.List[str]`), generic `[T]` syntax on functions/classes.
52+
- **Type hints** on public APIs; loose typing inside private methods OK.
53+
- **Async** for any function that crosses the server/client boundary
54+
(`@app.server.rpc`, `@app.server.realtime`, `@app.client.callback`,
55+
`@app.client.realtime`, lifecycle handlers). Sync handlers are rejected
56+
at decoration time with `ValueError`.
57+
- **Decorator order** matters for `@app.local`: `@app.local` goes
58+
*outside* `@dataclass`. The standalone `local()` in `state.py` is the
59+
bare-decorator version; `App.local` wraps it to also register the class
60+
for bundle transpilation.
61+
- **Module-level defs** for any class/function passed to `@app.local` or
62+
`@app.client.*`. The bundle generator dedents source so nested defs
63+
work in tests, but real apps should define these at module scope for
64+
predictability and IDE support.
65+
- **Formatting** via `ruff format`. CI enforces it. Run `make format`
66+
before pushing or let `make` (default = `test-unit`) fail loudly.
67+
- **No JS framework**. No htmx. If you find yourself reaching for one,
68+
build the missing primitive in Python instead.
69+
70+
## Common workflows
71+
72+
### Run the test suite
73+
74+
```bash
75+
make # = make test-unit (ruff format-check + pytest --cov)
76+
make test-all # also collects tests outside tests/ (rarely needed)
77+
```
78+
79+
CI runs the same gate on every push/PR (`.github/workflows/tests.yml`).
80+
81+
### Add a feature
82+
83+
1. Read the relevant `issues/<n>-...md` design doc if one exists; otherwise
84+
draft one before coding non-trivial surface.
85+
2. Update `roadmap.md` checkboxes when shipping a phase item.
86+
3. Pin behavior with a test in the matching file
87+
(`tests/test_<surface>.py`). Coverage gates aren't enforced but
88+
leaving Pyodide-only paths at 0% is the established norm — that's
89+
what the deferred "Pyodide simulator" slice is for.
90+
91+
### Fix a bug found in production usage
92+
93+
If the bug shows up in an example (e.g. `examples/*.py`), the example is
94+
documentation; fix it too. If the bug is in the framework, add a
95+
regression test pinning the new behavior before flipping the production
96+
code — characterization first prevents accidental re-regression.
97+
98+
### Release
99+
100+
```bash
101+
NEW_VERSION=1.3.0 make release
102+
```
103+
104+
This:
105+
1. Verifies formatting + runs the full suite.
106+
2. Bumps `pyproject.toml` and `violetear/__init__.py` (they must stay in sync).
107+
3. Commits, tags `v1.3.0`, pushes commit + tag, creates a GitHub release.
108+
109+
Never bump versions manually — the makefile is the single source of truth
110+
so the two version files don't drift.
111+
112+
## Surfaces with limited test coverage
113+
114+
Be extra careful when touching these — regressions are easy because the
115+
test suite won't catch them:
116+
117+
- **`client.py`** (hydration, ReactiveRegistry, socket listener) — pure
118+
Pyodide code, no server-side tests. Bundle-generation tests pin *what
119+
gets emitted* but not the runtime behavior.
120+
- **`dom.py` `DOMElement`** — same, pure Pyodide.
121+
- **`storage.py`** — has a server-side memory fallback for testing but
122+
it's untested today.
123+
- **Style/StyleSheet fluent methods** (`.padding`, `.font`, `.border`,
124+
`.flex`, …) — black-box tested against fixtures in `tests/test_examples.py`
125+
via expected `.css` outputs in `tests/expected_outputs/`, no unit tests.
126+
- **`Component` subclasses + `ElementSet.spawn`** — pattern exists in
127+
`markup.py` but no examples or tests exercise it.
128+
129+
## Things to NOT do
130+
131+
- Don't broadcast from `@app.server.on("startup")`. At startup there are
132+
zero active websocket connections; clients reconnect after startup. Use
133+
`@app.server.on("connect")` + `.invoke(client_id, ...)` to greet new
134+
clients, or `.broadcast(...)` from inside a request handler when there
135+
are already-connected clients.
136+
- Don't put PII or secrets in `examples/`. They're shipped in PyPI sdists.
137+
- Don't add a new third-party runtime dependency without first checking
138+
whether the workspace already has a sibling lib (in `repos/`) that
139+
provides the capability. Cross-repo reuse: `vault/Atlas/Architecture/`
140+
may have a relevant design doc.
141+
142+
## Know-how index
143+
144+
*(Empty for now. Add procedure docs to `know-how/<topic>.md` as recurring
145+
tasks emerge — testing a new client-side feature, debugging a Pyodide
146+
bundle failure, profiling render performance, etc. Each entry here gets a
147+
short "when to reach for it" line so future agents can match by intent.)*

0 commit comments

Comments
 (0)