7b5d58686e
Captures two carve-outs to aish's "non-PR-flow repo" default: - Feature requests and bugs go to git.reauktion.de/marfrit/aish/issues rather than direct-implement-in-band. Tag `architecture` for cross- phase concerns. Aligns with the fleet-wide bug-filing convention from the `his` cheatsheet; this row extends it to features for aish. - Review-required iteration opens a PR (authored as claude-<host>, marfrit reviews, self-approval forbidden). PR #1 was the precedent. Both are opt-in; direct-to-main remains the default for autonomous work that doesn't need a feedback loop. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
238 lines
8.8 KiB
Markdown
238 lines
8.8 KiB
Markdown
# CLAUDE.md — aish project handoff
|
|
|
|
You are continuing work on **aish**, an AI-augmented conversational shell
|
|
implemented in LuaJIT. This file is auto-loaded when a Claude session opens
|
|
a clone of this repo. Read it once at session start.
|
|
|
|
---
|
|
|
|
## 1. Read these first, in order
|
|
|
|
1. **`docs/PHASE0.md`** — locked substrate. Every architectural decision is
|
|
here. Do not contradict it without amending it.
|
|
2. **`README.md`** — human-facing project summary and orientation.
|
|
3. **`config.lua`** — the runtime model registry. Endpoints reflect a
|
|
specific LAN; the user may have already adapted yours.
|
|
|
|
If a question seems open after reading those three, **ask the user a
|
|
single focused question** rather than guessing. Cost of asking is one
|
|
turn; cost of building on a wrong assumption is half a phase.
|
|
|
|
---
|
|
|
|
## 2. Where you are in the phase loop
|
|
|
|
aish follows an **8(+1) phase loop**:
|
|
|
|
```
|
|
0 substrate → 1 formulate → 2 analyze → 3 baseline → 4 plan
|
|
→ 5 review → 6 implement → 7 verify → 8 memory-update
|
|
(+1 reflect)
|
|
```
|
|
|
|
Loopbacks:
|
|
- `3 → 1` if baseline data invalidates the formulation
|
|
- `7 → 4` if verification fails — fix the plan, not the substrate
|
|
- `any → 0` if a substrate fact turns out to be wrong
|
|
|
|
Don't skip phases. Phase 0 is done (the manifest is locked); your starting
|
|
position depends on what's already in the tree.
|
|
|
|
Check the state by reading `docs/` and `git log --oneline`. If only
|
|
PHASE0.md exists in `docs/` and every module raises NotImplemented, **you
|
|
are at Phase 0 → Phase 1 transition**: the substrate is locked, no module
|
|
is implemented, your job is to write the Phase 0 implementation per the
|
|
manifest.
|
|
|
|
If you find phase docs `docs/PHASE1.md`, `docs/PHASE2.md` etc., follow
|
|
their state.
|
|
|
|
---
|
|
|
|
## 3. Source-of-truth invariants — do not violate without amending PHASE0.md
|
|
|
|
These are not stylistic preferences; they are decisions that downstream
|
|
phases depend on:
|
|
|
|
| Invariant | Where it's locked |
|
|
|---|---|
|
|
| LuaJIT 2.x only — no PUC-Rio Lua-only constructs | §3 |
|
|
| FFI only — no compiled C extensions, no `luarocks` packages | §3 |
|
|
| Module file names in §4 are stable across phases | §4 |
|
|
| `/v1/chat/completions` is the broker contract | §6 |
|
|
| `CMD:` (exact prefix, single space) is the command-extraction marker | §6 |
|
|
| Config is plain Lua loaded with `dofile`, not JSON/YAML | §3, §10 |
|
|
| `cd` is intercepted via libc `chdir`, not delegated to `popen` | §7 |
|
|
| Phase 0 has no disk I/O for history (memory only) | §8 |
|
|
|
|
If a Phase N implementation needs to break one of these, **amend
|
|
PHASE0.md in the same commit and call out the change in the commit
|
|
message**. Don't silently diverge.
|
|
|
|
---
|
|
|
|
## 4. Implementation order for Phase 0
|
|
|
|
Bottom-up beats top-down for this codebase. Suggested ordering:
|
|
|
|
1. `ffi/libc.lua` — `chdir`, `strerror` work; verifiable in isolation.
|
|
2. `ffi/readline.lua` — `readline()`, `add_history()`, `free()` work; test
|
|
with a tiny REPL stub before wiring `repl.lua`.
|
|
3. `ffi/curl.lua` — easy interface, blocking POST with response capture
|
|
into a Lua string. Test against any local llama-server with a curl
|
|
one-liner side-by-side.
|
|
4. `context.lua` — pure data structure, trivial to unit-test.
|
|
5. `executor.lua` — `popen` wrapper, `cd` interception (uses libc.chdir),
|
|
`CMD:` line extraction.
|
|
6. `router.lua` — pure function; classify(line, config) → (kind, payload).
|
|
7. `broker.lua` — uses `ffi/curl.lua` + JSON encode/decode. **You will
|
|
need a JSON library** — see §6 below.
|
|
8. `renderer.lua` — output formatting; trivial.
|
|
9. `repl.lua` — wires everything via the dispatch table.
|
|
10. `main.lua` — already mostly there; finalize once `repl.run` exists.
|
|
|
|
Don't write all ten in one commit. One commit per module, build the
|
|
chain by passing through; each commit should leave the tree in a state
|
|
where `luajit main.lua` either runs further than the previous commit or
|
|
fails with the next NotImplemented.
|
|
|
|
---
|
|
|
|
## 5. Testing approach
|
|
|
|
There is no test framework dependency by design. Testing is per-module
|
|
ad-hoc with `luajit -e 'local m = require("module"); ...'` from the repo
|
|
root, or a smoke `luajit main.lua` after each module lands.
|
|
|
|
For broker testing without burning model time: any of the local
|
|
llama-servers in `config.lua` will respond to a hand-crafted POST. Use
|
|
`curl -sS http://dirac.fritz.box:8081/v1/chat/completions -d '{...}'` to
|
|
generate a known-good reference, then compare your FFI output.
|
|
|
|
---
|
|
|
|
## 6. JSON encode/decode — undecided
|
|
|
|
The manifest doesn't pick a JSON library. LuaJIT 2.x has no built-in JSON.
|
|
Options:
|
|
|
|
- **`dkjson`** — pure Lua, single file, vendor it under `vendor/dkjson.lua`.
|
|
Slow but no dependency.
|
|
- **`cjson`** — fast, but it's a C extension. Violates §3 (no compiled
|
|
extensions). Skip unless you amend the manifest.
|
|
- **Hand-rolled minimal encoder** — viable since the broker payload shape is
|
|
small and well-defined; ~50 LOC.
|
|
|
|
Recommend dkjson vendored. Decide and add a note to PHASE0.md §3 in the
|
|
same commit.
|
|
|
|
---
|
|
|
|
## 7. When you hit ambiguity
|
|
|
|
The user (mfritsche) prefers being asked over being assumed-about. The
|
|
phrase "Ask readily — prefer quick question over 3+ guessing attempts"
|
|
applies. Concrete pattern:
|
|
|
|
- If the question affects only the current commit: ask.
|
|
- If it affects a future phase: log it in `docs/PHASE0.md` §13 (Open
|
|
Questions) with target phase, keep working.
|
|
- If it affects multiple existing modules: stop, ask before refactoring.
|
|
|
|
Don't suggest pausing the session. Don't suggest "let's pick this up
|
|
tomorrow". Don't pre-emptively defer work the user hasn't asked you to
|
|
defer. The user controls pace.
|
|
|
|
---
|
|
|
|
## 8. Commit style
|
|
|
|
Imperative subject, file-scoped where possible. Examples:
|
|
|
|
- `executor: implement io.popen wrapper with stderr merge`
|
|
- `ffi/curl: blocking POST with header list and response buffer`
|
|
- `repl: wire router → executor → broker dispatch`
|
|
- `phase0 amendment: vendor dkjson under vendor/`
|
|
|
|
Body explains the *why* if non-obvious. Reference PHASE0.md sections by
|
|
number when relevant.
|
|
|
|
Co-Authored-By trailer on Claude-authored commits:
|
|
|
|
```
|
|
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|
```
|
|
|
|
(or whichever model you actually are; check before substituting.)
|
|
|
|
---
|
|
|
|
## 9. What aish does NOT do — out of scope, all phases
|
|
|
|
These are listed in PHASE0.md §12. Briefly:
|
|
|
|
- Does not manage llama.cpp lifecycle (assumed externally running)
|
|
- Does not implement model inference
|
|
- Is not a multiplexer (no tmux semantics)
|
|
- Is not a sandbox (no namespaces, no seccomp)
|
|
|
|
If you find yourself implementing any of those, stop — that's a different
|
|
project.
|
|
|
|
---
|
|
|
|
## 10. The model serving aish (typically)
|
|
|
|
aish targets local llama.cpp endpoints. The committed `config.lua`
|
|
references the user's home network (`dirac.fritz.box`,
|
|
`hossenfelder.fritz.box`). The user's other Claude sessions have
|
|
established that small Q4_K_M models (Qwen2.5-Coder-7B and similar) have
|
|
**variance issues on code generation tasks** — the same prompt can yield
|
|
both correct and broken code across rolls. Practical implications for
|
|
aish:
|
|
|
|
- Default `temperature` to `0.2` or lower for code tasks.
|
|
- Don't assume the model output is correct — validate before exec.
|
|
- The `confirm_cmd = true` default in `config.shell` is there for this
|
|
reason; don't disable it without a deliberate UX change.
|
|
|
|
This isn't paranoia, it's a measured property of the local model class
|
|
the user runs.
|
|
|
|
---
|
|
|
|
## 11. Identity
|
|
|
|
If this is a session running on a fleet host other than the user's
|
|
primary Claude window, your Gitea identity is `claude-<hostname>`. For
|
|
aish (a non-PR-flow repo), commits as that identity are fine without a PR.
|
|
If you need to push and lack credentials, use a Gitea Personal Access
|
|
Token in the URL: `git push https://<user>:<token>@git.reauktion.de/marfrit/aish.git main`.
|
|
|
|
The user has marfrit-level credentials available via a separate channel
|
|
if needed for repo-admin operations.
|
|
|
|
---
|
|
|
|
## 12. Contribution flow
|
|
|
|
Default for direct work: **commit straight to `main`**. No PR, no issue
|
|
gate. This is what "non-PR-flow repo" means in §11.
|
|
|
|
Two opt-in carve-outs:
|
|
|
|
- **Feature requests and bugs → Gitea issues** at
|
|
`git.reauktion.de/marfrit/aish/issues`. Don't implement feature
|
|
requests in-band; file the issue, let marfrit triage. Tag
|
|
`architecture` for cross-phase concerns. (Bug-filing convention is
|
|
fleet-wide per the `his` cheatsheet; this row extends it to features
|
|
for aish specifically.)
|
|
- **Review-required iteration → PR**. When the medium needs to be the
|
|
diff (inline comments per finding, refinable wording), open a PR
|
|
authored as `claude-<host>` and let marfrit review. Self-approval
|
|
forbidden. PR #1 (`marfrit/aish#1`, 2026-05-10) set the precedent —
|
|
the MCP phase-2 question batch surfaced by review of `013c625`.
|
|
|
|
When in doubt whether something is a feature request vs. an in-band fix,
|
|
ask. Cheaper than the alternatives.
|