A lightweight coding and automation agent in one CLI binary. A multi-agent harness. Run locally or over SSH.
The project's README from github.com/guregodevo/memdoor. As one markdown file: README.md.
Your daemon agents on every door.
A coding and automation agent in one CLI binary. No Docker or Python. Runs on this machine or over SSH on another. Clients: terminal, IDE, phone, script, CI, schedule. On your gateway. On your key.
A headless CLI with multi-agent harness
Five Qwen3.8-27B agents beat Fable 5 on LiveCodeBench Hard, as a Memdoor workflow. GVS5H's harness rebuilt with the authors' exact prompts and loop. The first ten problems of their list, five passes each: a mean of 9.8 of 10. The authors' own harness scored 9.6 and Fable 5 in a single call 8.0, the gap the authors measured on these ten (across their full 100: 92.4 and 90.4). All 50 runs are published: every request, reply, program and grader output. The workflow is YAML and names no model. Point it at yours, or at a local one with
memdoor connect local(Ollama, llama.cpp, vLLM, LM Studio; how to run it on an open-weight model, no key). examples/workflows/team-solve · the result page · the HN thread
On this machine:
curl -fsSL https://memdoor.ai/install.sh | bash
export OPENROUTER_API_KEY=sk-or-... # or ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, …
# or no key: memdoor connect local # an open-weight model on this machine — https://memdoor.ai/docs/open-weight
cd your-project && memdoor # the first run sets the machine up
On a box reachable by ssh, nothing installed there:
curl -fsSL https://memdoor.ai/install.sh | bash # here, once
memdoor --gateway ssh://you@box # installs memdoor on the box, starts its gateway, opens the window on it
memdoor --gateway ssh://you@box connect openrouter # your key, kept on the box; every turn there runs on it
memdoor --gateway ssh://you@box run "fix the failing test" # the same box from a script or CI

Decision model. Jev (TypeSafe) answers a typed question about a turn
with a calibrated probability in under half a second. Judged reads: search,
file and log reads return what counts. Per-turn toolbox: only the tools the
turn needs are sent. Stall detection: a turn that stops making progress ends.
44 paired runs, decisions off and on: 22 of 22 passed each way; a codebase
question 54,661 to 14,367 input tokens (−74%); an edit with a test and ten
one-file fixes read the same files either way (within ±11%)
(docs/features/DECIDE.md).
Workflows, the deterministic harness. Say the steps; the coder writes one
YAML per step. mario runs the graph.
Independent steps run in parallel. A step is done when its check passes. A
gate waits for approval with the diff. A failed run resumes at the failed
step. Started by hand, from CI or on local cron
(docs/features/WORKFLOWS.md). Workflows, not
skills: the write-up.
Examples, each run before it was added:
examples/workflows/. The nightly grade step,
examples/workflows/nightly-rule/steps/grade.yaml:
type: agent
prompt: |
Today's partition is {{.partition}}.
Read rules/{{.partition}}.md and grade today's trading rule: assess it
briefly (clarity, risk profile, plausibility) and write a JSON object
{"score": <0-100 integer>, "verdict": "<one sentence>"} into
grades/{{.partition}}.json (create grades/ if needed).
requires:
- table_pattern: build
target:
# run by the engine, not by the agent: the grade must exist and be newer than step 1's start stamp
command: test "grades/{{.partition}}.json" -nt "rules/{{.partition}}.start" && test -s "grades/{{.partition}}.json"
timeout: 10m
The review loop recorded (findings verified by running, a gate, the fixes applied): memdoor.ai/workflows.
| Command | What it does |
|---|---|
/model |
The agent's ladder, cheapest rung first. Pin any model of your providers. List prices |
/connect |
Add a provider: OpenRouter, Anthropic, OpenAI, Gemini, DeepSeek, Baseten, Groq, xAI, any OpenAI-compatible endpoint, a company AI gateway. /connect local: a runtime on this machine or the box (Ollama, llama.cpp, janis), no key. /connect chatgpt: a ChatGPT Plus/Pro plan, no key |
/workflow |
The project's workflows and runs. Enter opens a run's graph, a approves a gate, /workflow:<name> runs one |
/usage |
This month on your key, per model, and what the decision model kept out of the bill |
/remote |
This conversation on your phone: a link and a QR code, the terminal itself, end-to-end encrypted |
/remote view |
A watch-only link: live, no typing, no account, up to 200 viewers. ?live=1 is the terminal alone, for a stream or OBS |
/share |
A read-only link to the conversation, encrypted, secrets removed. /unshare deletes it |
/files or ctrl+f |
The project's files, the ones this conversation read or changed first, each with what happened to it. Enter previews, ctrl+d diffs, ctrl+e opens in $EDITOR, tab puts @path in the prompt |
/graph or ctrl+g |
The turn as a graph: the reads, the edits that depended on them, the runs that depended on the edits, the failing check in red |
/mcp |
MCP servers from a URL, a command or a .mcp.json snippet |
/help |
The rest |
Esc interrupts. ctrl+o expands tool frames. Shift+Tab sets reasoning
effort. @path mentions a file. MEMDOOR_APPROVE=changes asks before every
command and write.
memdoor acp serves the coder over the Agent Client
Protocol. Zed and JetBrains host it
natively. VS Code: an ACP client extension (for example "ACP Client") and one
setting:
"acp.agents": { "Memdoor": { "command": "memdoor", "args": ["acp"] } }
A session is a conversation on the local gateway. A prompt is a turn in the editor's workspace folder. Text, tool calls and approvals show as the editor's own. Steps: memdoor.ai/docs/editor.
memdoor run "make the retry wait configurable and add a test" # a headless turn, no window
git diff | memdoor run "review this diff; one line per finding" # stdin is the input
memdoor run --json "fix the failing test" | jq 'select(.event=="done")'
memdoor workflow run release --wait # progress on stderr, results on stdout
memdoor remote --last # the link /remote gives, on stdout; the gateway holds the run for your phone
memdoor remote --view --last # the watch-only link: an audience, or a pair of eyes
Exit code: 0 checked, 2 unverified or a failing check, 3 a question nobody
answered (--yes answers it), 1 an error, 130 interrupted. The gateway starts
if none is running. memdoor resume opens any run.
Headless, then attached.
One step. Your key as the secret. Nothing added to the repo (Marketplace):
on: pull_request
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: guregodevo/memdoor-action@v1
with:
workflow: pr-review
openrouter-api-key: ${{ secrets.OPEN_ROUTER_API_KEY }}
Built in:
pr-triage: ready for review, needs work, or likely slop, from checks run in the job (the tests, claimed tests that are not there, functions nothing calls).pr-review: findings verified by running the code; the job fails only on a blocker.security-review: secrets, injection, path traversal, missing authorization.write-tests: tests for what the change touches; the job fails when one shows the change is wrong.pr-description: title, What, Why, How to test, Risk.explain-failure: a failed run's logs and the diff; the cause, file:line, the fix.issue-triage: labels, kind, summary, duplicates.fix-tests: finds the test command, fixes the code until the tests pass, leaves the fix in the working tree.release-notes: commits since the last tag as Added / Changed / Fixed.local-model: Qwen3-8B-4bit in place of the key: the model runs inside the
runner (janis, one file, cached), one
call. On a free runner: an obvious and a subtle bug found in about a minute
each; a correct change can be flagged as a blocker. A first pass.
workflow: <name> runs yours from .memdoor/workflows/<name>/. Exit code:
0 done, 2 failed, 1 stopped, 3 stopped at an approval gate. The job summary
holds the review, the fix or the notes. Trigger on pull_request, never
pull_request_target: a fork's pull request gets no secrets.
A provider key in the environment (OPENROUTER_API_KEY, ANTHROPIC_API_KEY,
OPENAI_API_KEY, GEMINI_API_KEY, …) or memdoor connect. No key: the
first memdoor signs in with OpenRouter in the browser, from this machine,
over ssh or on a box. No credit: a free model, 50 requests a day; its hosts
train on what they are sent. For a trial, not private code.
Local: memdoor connect local connects a model on this machine
(janis, Ollama, llama.cpp, LM Studio).
Nothing leaves it. janis: one Go server, open models on a Mac's GPU through
MLX or an NVIDIA box through CUDA, serves chat and the decision model, no
key; Qwen3-Coder-30B-A3B on a $0.71-an-hour Google L4. On a box: memdoor --gateway ssh://you@box connect local. Peers: memdoor peers add box http://box:18789 --dir ~/app names the box; @box:coder … in any
conversation runs the turn there and returns the answer.
Files, sessions and commands stay on your machine. What the model reads goes
to the provider. OpenRouter: every request carries data_collection: deny;
hosts that train on paid inputs are kept out of the ladders. Exception: a
:free model, pinned or answering for an account with no credit; its hosts
train on what they are sent, the request says so (allow), Memdoor warns at
the pin or at connect. Vendor key or company gateway: nothing else is
contacted. docs/SECURITY.md lists the hosts the binary
can name; a test fails the build on a new one.
Go 1.25:
git clone https://github.com/guregodevo/memdoor && cd memdoor
make build # ./memdoor, stamped with the tag it was built from
cp memdoor ~/.local/bin/ # or anywhere on your PATH
cmd/cli/ the CLI (cobra): tui, model, workflow, cron, account, …
gateway/ the local gateway: agent runtime, tools, providers, workflows
pkg/ the domain: decision, metering, plan, workflow (the mario task factory), …
web/ the memdoor.ai site and the served docs (React, Vite)
scripts/ install.sh, install.ps1, deploy.sh
docs/ features, reference, ADRs
examples/ workflows built by the coder and run, to copy into a project
Apache License 2.0: LICENSE, NOTICE. Public repository: github.com/guregodevo/memdoor. Issues go there.
A lightweight coding and automation agent in one CLI binary. A multi-agent harness. Run locally or over SSH.