This file is the door for any AI coding agent working in this repo. Read it
first. Other tools (Codex, OpenCode, Cursor, Aider) auto-load it; for Claude
Code it's loaded via the workspace convention in ~/Workspace/CLAUDE.md.
There is also an AGENT.md (singular) — Alex's personal protocol describing
how to think before coding (Understand → Plan → Develop → Document). That
file is voice/process; this file (AGENTS.md, plural) is structural.
A full-stack isomorphic Python web framework. FastAPI + uvicorn on the
server; Pyodide bundle on the client. Ships a server-side HTML builder
(markup.Element, HTML.div(...)), a reactive-state layer (@app.local +
ReactiveProxy) that emits data-bind-* annotations during SSR and
hydrates them on the client, a DOMElement wrapper for imperative
browser-side DOM work, a WebSocket RPC bus (@app.server.rpc /
@app.client.realtime), a CSS DSL (Style, StyleSheet), and PWA
scaffolding. No JS framework, no templates, no htmx.
Vault node: vault/Efforts/Repos/violetear.md (in Alex's workspace).
violetear/ package source
app.py App, ClientRegistry, ServerRegistry, SocketManager, bundle gen
markup.py Element, Document, HTML builder, Component
state.py @local decorator, ReactiveProxy, LeafProxy
client.py Pyodide-side: ReactiveRegistry, hydrate(), socket listener
dom.py Pyodide-side: DOMElement, DOM static factory, Event protocol
storage.py Pyodide-side: store/session wrappers around localStorage
style.py fluent style builder
stylesheet.py stylesheet builder, selectors
color.py Color class + Colors named-color registry
pwa.py Manifest, ServiceWorker generators
presets.py FlexGrid, SemanticDesign, UtilitySystem, Atomic
tests/ pytest suite
docs/ quarto docs site + example .py files (consumed by test_examples.py)
examples/ canonical demos, one per tier (01_static → 05_realtime)
issues/ design docs for unimplemented features
.github/workflows/ CI (ruff format-check + pytest on push/PR)
roadmap.md v1.0 roadmap (Phases 1-4)
AGENT.md Alex's code-agent thinking protocol (orthogonal to this file)
- Python 3.12+ required. Use modern features:
match,list[str](nottyping.List[str]), generic[T]syntax on functions/classes. - Type hints on public APIs; loose typing inside private methods OK.
- Async for any function that crosses the server/client boundary
(
@app.server.rpc,@app.server.realtime,@app.client.callback,@app.client.realtime, lifecycle handlers). Sync handlers are rejected at decoration time withValueError. - Decorator order matters for
@app.local:@app.localgoes outside@dataclass. The standalonelocal()instate.pyis the bare-decorator version;App.localwraps it to also register the class for bundle transpilation. - Module-level defs for any class/function passed to
@app.localor@app.client.*. The bundle generator dedents source so nested defs work in tests, but real apps should define these at module scope for predictability and IDE support. - Formatting via
ruff format. CI enforces it. Runmake formatbefore pushing or letmake(default =test-unit) fail loudly. - No JS framework. No htmx. If you find yourself reaching for one, build the missing primitive in Python instead.
make # = make test-unit (ruff format-check + pytest --cov)
make test-all # also collects tests outside tests/ (rarely needed)CI runs the same gate on every push/PR (.github/workflows/tests.yml).
- Read the relevant
issues/<n>-...mddesign doc if one exists; otherwise draft one before coding non-trivial surface. - Update
roadmap.mdcheckboxes when shipping a phase item. - Pin behavior with a test in the matching file
(
tests/test_<surface>.py). Coverage gates aren't enforced but leaving Pyodide-only paths at 0% is the established norm — that's what the deferred "Pyodide simulator" slice is for.
If the bug shows up in an example (e.g. examples/*.py), the example is
documentation; fix it too. If the bug is in the framework, add a
regression test pinning the new behavior before flipping the production
code — characterization first prevents accidental re-regression.
NEW_VERSION=1.3.0 make releaseThis:
- Verifies formatting + runs the full suite.
- Bumps
pyproject.tomlandvioletear/__init__.py(they must stay in sync). - Commits, tags
v1.3.0, pushes commit + tag, creates a GitHub release.
Never bump versions manually — the makefile is the single source of truth so the two version files don't drift.
Be extra careful when touching these — regressions are easy because the test suite won't catch them:
client.py(hydration, ReactiveRegistry, socket listener) — pure Pyodide code, no server-side tests. Bundle-generation tests pin what gets emitted but not the runtime behavior.dom.pyDOMElement— same, pure Pyodide.storage.py— has a server-side memory fallback for testing but it's untested today.- Style/StyleSheet fluent methods (
.padding,.font,.border,.flex, …) — black-box tested against fixtures intests/test_examples.pyvia expected.cssoutputs intests/expected_outputs/, no unit tests. Componentsubclasses +ElementSet.spawn— pattern exists inmarkup.pybut no examples or tests exercise it.
- Don't broadcast from
@app.server.on("startup"). At startup there are zero active websocket connections; clients reconnect after startup. Use@app.server.on("connect")+.invoke(client_id, ...)to greet new clients, or.broadcast(...)from inside a request handler when there are already-connected clients. - Don't put PII or secrets in
examples/. They're shipped in PyPI sdists. - Don't add a new third-party runtime dependency without first checking
whether the workspace already has a sibling lib (in
repos/) that provides the capability. Cross-repo reuse:vault/Atlas/Architecture/may have a relevant design doc.
(Empty for now. Add procedure docs to know-how/<topic>.md as recurring
tasks emerge — testing a new client-side feature, debugging a Pyodide
bundle failure, profiling render performance, etc. Each entry here gets a
short "when to reach for it" line so future agents can match by intent.)