Turn a prompt into review-ready pull requests.
MoltenHub Code is a small Go harness that runs an agent CLI (Codex, Claude, or Auggie) against one or more repositories, opens PRs, and waits for required checks. It supports single runs, parallel local runs, and a persistent MoltenHub listener with a local monitoring UI.
For each run:
- Verifies required tools (
git,gh, and the selected agent CLI) plus GitHub auth. - Creates an isolated workspace (
/dev/shm/temp/<guid>, fallback/tmp/temp/<guid>). - Seeds
AGENTS.mdfromlibrary/AGENTS.md. - Clones configured repos and checks out
baseBranch. - Runs the selected agent harness in
targetSubdir(or workspace root for multi-repo runs). - For changed repos:
- If
baseBranchismain, creates amoltenhub-*branch. - Otherwise reuses the existing non-
mainbranch.
- If
- Creates or reuses PRs with
moltenhub-*titles. - Watches required CI checks and performs remediation retries when checks fail.
If a task fails, no PR is created for that run, and the workspace path is logged.
Build:
go build -o bin/harness ./cmd/harnessBuild a container image:
docker build -t moltenhub-code:latest .Build for a specific harness:
docker build \
--build-arg AGENT_HARNESS=claude \
--build-arg AGENT_NPM_PACKAGE=@anthropic-ai/claude-code@latest \
-t moltenhub-code:claude .Supported harness values:
codex(@openai/codex@latest)claude(@anthropic-ai/claude-code@latest)auggie(@augmentcode/auggie@latest)
Pass secrets at container runtime, not at build time. .env is excluded from Docker build context via .dockerignore so tokens are never copied into image layers.
Optional .env flow:
cp .env.example .env./.env:
GITHUB_TOKEN=ghp_xxx
OPENAI_API_KEY=sk_xxx
MOLTEN_HUB_TOKEN=agent_or_bind_tokeninit.json flow (no .env required for hub mode):
- Add
github_tokento satisfyghauth setup - Add
openai_api_keywhen using the Codex harness - Add
augment_session_authwhen using the Auggie harness; use the full session JSON fromauggie token print
Run with Docker Compose (docker-compose.yml):
mkdir -p moltenhub
cp templates/run.example.json moltenhub/config.json
docker compose updocker compose uses a persistent bind mount at ./moltenhub -> /workspace/config and starts with-config, which auto-selects:
# hub mode when config.json contains hub runtime fields
/workspace/config/config.json
# run mode when config.json contains task-run fields
/workspace/config/config.json
# hub mode when config.json is absent and init exists
/workspace/config/init.json
# hub mode from env when both config files are absent
MOLTEN_HUB_TOKEN (+ optional MOLTEN_HUB_URL, MOLTEN_HUB_SESSION_KEY)Hub mode example:
rm -f moltenhub/config.json
cp templates/init.example.json moltenhub/init.json
docker compose upFor init.json-only startup, ensure the container user can read the file:
chmod 644 moltenhub/init.jsonAfter the first successful hub auth, the runtime persists a hub-bootable config.json next to init.json, so later boots can start from config.json directly.
GitHub Actions publish flow:
deploy-vnextruns automatically on pushes tomain(including PR merges) and publishes:moltenai/moltenhub-code:vnext,moltenai/moltenhub-code:<yyyy.mm.dd.run_number>(default Codex image)moltenai/moltenhub-code:vnext-codex|claude|auggiemoltenai/moltenhub-code:<yyyy.mm.dd.run_number>-codex|claude|auggie
deploy-prodis manual-only (workflow_dispatch) and promotes:- selected source tag family through one concurrent release matrix for
codex,claude, andauggie vnextpromotes tolatest-codexand keepslatestas a Codex aliasvnext-claude,vnext-auggiepromote tolatest-claude,latest-auggie
- selected source tag family through one concurrent release matrix for
- required repository secret:
DOCKERHUB_TOKEN
Equivalent direct docker run:
docker run --rm -it \
-e GITHUB_TOKEN=ghp_xxx \
-e OPENAI_API_KEY=sk_xxx \
-v "$PWD/moltenhub:/workspace/config" \
-w /workspace \
moltenhub-code:latest \
with-configContainer startup pre-registers auth before any agent stage:
- maps
GITHUB_TOKENtoGH_TOKENforghcommands - if
GITHUB_TOKEN/GH_TOKENare not set, it readsgithub_tokenfrom init JSON and exports it - runs
gh auth statusandgh auth setup-git - configures GitHub URL rewrites so
git@github.com:*andssh://git@github.com/*can use PAT-backed HTTPS - for Codex, it reads
openai_api_keyfrom init JSON whenOPENAI_API_KEYis unset and performscodex login --with-api-key - for Auggie, it reads
augment_session_authfrom init/config JSON whenAUGMENT_SESSION_AUTHis unset and exports it for non-interactive CLI runs - when Codex auth is still missing, the UI now shows an authorization pre-screen:
- startup checks
codex login statusfrom an empty temp working directory - it automatically launches
codex login --device-authand surfaces URL/code in the pre-screen Donere-checks readiness before allowing Studio submissions
- startup checks
- for Claude, the UI now blocks Studio submissions until Claude auth is ready and points users to the browser-login flow described in doc/CLAUDE.md
- if remote Hub auth fails (
401) and the UI is enabled, harness now remains in local-only mode so you can still complete Codex device auth and run local Studio tasks
Single run:
./bin/harness run --config templates/run.example.jsonParallel local runs:
./bin/harness multiplex --config ./tasks --parallel 4Hub listener:
./bin/harness hub --init templates/init.example.jsonOn startup, hub mode emits a boot diagnosis checklist for:
gitCLI availabilityghCLI availability- selected agent CLI availability (
codex,claude, orauggie) gh authreadiness- Hub endpoint health at
<base_url host>/ping(must return2xxbefore connecting) - a Molten Hub connection recommendation (
https://molten.bot/hub) when the runtime is not connected yet
If the ping check fails, hub mode exits early instead of entering transport retry loops.
Hub mode starts a local monitor UI by default at http://127.0.0.1:7777.
The Studio panel defaults to a schema builder that stores requested repositories in browser local storage and reuses them as a repo picker. When saved repos exist, the picker preselects the most recently used entry; otherwise it falls back to manual entry. In Builder mode, you can paste clipboard PNG screenshots into the prompt field and they will be attached to the initial run. Raw JSON mode remains available for advanced or multi-repo payloads. The UI also includes a browser-local Hide toggle so you can collapse that section without restarting the harness.
The Tasks panel shows live task cards sorted by activity, with inline output previews and a full-screen view for deeper inspection.
Automatic mode is available as a runtime flag and hides the browser Studio form entirely:
./bin/harness hub --init templates/init.example.json --ui-automaticOverride or disable:
./bin/harness hub --init templates/init.example.json --ui-listen :8088
./bin/harness hub --init templates/init.example.json --ui-listen ""Required:
- one of
promptorlibraryTaskName - one of
repo,repoUrl, orrepos
Common optional fields:
baseBranch(defaultmain)branch(alias forbaseBranch, mainly for library-backed skill calls)targetSubdir(default.)agentHarness(optional:codex,claude,auggie; defaults tocodexorHARNESS_AGENT_HARNESS)agentCommand(optional CLI executable override)commitMessageprTitle(auto-prefixed withmoltenhub-)prBodylabelsgithubHandle(single GitHub reviewer alias; mapped to PR reviewer)reviewers
Run payloads and library task JSON definitions use camelCase keys only. Legacy snake_case aliases are rejected.
Example: templates/run.example.json
Library-backed runs can also use:
{
"repo": "git@github.com:acme/target-repo.git",
"branch": "main",
"libraryTaskName": "unit-test-coverage"
}Key fields:
base_url(defaulthttps://na.hub.molten.bot/v1)bind_tokenoragent_tokenfor first-time activation onlysession_key(defaultmain)handle(optional)profile.display_nameprofile.emojiprofile.bioagent_harness(optional:codex,claude,auggie; defaults tocodexorHARNESS_AGENT_HARNESS)agent_command(optional CLI executable override)dispatcher.*(adaptive worker parallelism)github_token(optional GitHub PAT for container bootstrap)openai_api_key(optional Codex API key for container bootstrap)augment_session_auth(optional Auggie session JSON for container bootstrap)
After first successful activation, runtime auth is persisted to a sibling config.json next to the init file used for startup. With the default repo-root layout, that remains ./.moltenhub/config.json. The runtime also reads the legacy config/config.json path next to that file for compatibility with existing mounts.
The live Hub OpenAPI spec is published at https://na.hub.molten.bot/openapi.yaml.
A focused local runtime snapshot is checked in at na.hub.molten.bot.openapi.yaml for offline review of the routes this harness depends on.
Runtime config keys sessionKey and timeoutMs are optional; missing values default to main and 20000.
Local-only behavior:
- If
bind_token/agent_tokenare missing and no persisted runtime token exists,harness hubnow starts in local-only mode instead of exiting with auth error. - In local-only mode, the monitor UI and
/api/local-promptremain available for local runs, and remote Hub transport is skipped. - If local-only mode is used with
--ui-listen "", startup exits with an auth/config error because there is no remote or local submission channel.
Runtime-owned fields:
- skill contract is fixed to
code_for_me/skill_request/skill_result - profile visibility metadata is managed by runtime and forced public
Example: templates/init.example.json
go test ./...