feat(manifests): add 8 core-derived ACP agent manifests#17
Conversation
Consolidate the core-compatible agent manifests (claude-agent-acp, codex-acp, gemini, pi-acp, opencode, openhands, openclaw, mimo) as data-only manifest.toml files under their core-key directories. All 8 validate strictly against contract/manifest_schema.json (Draft 2020-12) and parse through the core consumer loader (benchflow.agents.manifest), each yielding a valid AgentConfig. As a discovery root these 8 register with 8 unique declared names and no collision. Note: a standalone, self-contained mimo manifest already lives at mimo-acp/manifest.toml and also declares name "mimo". The core-derived mimo lands at mimo/manifest.toml. The two share the declared name "mimo", so they must NOT sit under one BENCHFLOW_AGENTS_DIR discovery root (load_agents_from_dir raises duplicate-name). The core-compatible set is its own discovery root.
…ecoupled credential)
Greptile SummaryAdds eight
Confidence Score: 4/5Safe to merge with the caveat that opencode's API key mapping should be verified or fixed before relying on it in key-mapped deployments. Seven of the eight manifests are structurally sound and consistent with each other. The one concrete concern is opencode's missing BENCHFLOW_PROVIDER_API_KEY = OPENAI_API_KEY env_mapping entry — mimo is structurally identical and has it, and the opencode-proxy reads OPENAI_API_KEY directly; without the mapping the agent config is written without credentials. The e2e tests passed, but likely because the test environment had OPENAI_API_KEY already set in the process environment rather than relying on benchflow's mapping. The remaining findings (unescaped printf in codex-acp and openhands, duplicated bootstrap in pi-acp) are low-risk hardening items. opencode/manifest.toml — verify or add the missing BENCHFLOW_PROVIDER_API_KEY mapping. codex-acp/manifest.toml and openhands/manifest.toml — the printf-based JSON construction is worth hardening against unusual key values. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant BF as benchflow
participant ML as manifest loader
participant MF as manifest.toml
participant AG as agent process
BF->>ML: load_agent_manifest(BENCHFLOW_AGENTS_DIR)
ML->>MF: read contract_version, name, install_cmd, launch_cmd, env_mapping
ML-->>BF: manifest dataclass
BF->>BF: additive merge(manifest, core AGENTS entry)
note over BF: shim-only fields added from core
BF->>AG: run install_cmd
BF->>BF: "apply env_mapping BENCHFLOW_PROVIDER_* to agent-native vars"
BF->>AG: exec launch_cmd with mapped env vars
AG-->>BF: ACP stdio session
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant BF as benchflow
participant ML as manifest loader
participant MF as manifest.toml
participant AG as agent process
BF->>ML: load_agent_manifest(BENCHFLOW_AGENTS_DIR)
ML->>MF: read contract_version, name, install_cmd, launch_cmd, env_mapping
ML-->>BF: manifest dataclass
BF->>BF: additive merge(manifest, core AGENTS entry)
note over BF: shim-only fields added from core
BF->>AG: run install_cmd
BF->>BF: "apply env_mapping BENCHFLOW_PROVIDER_* to agent-native vars"
BF->>AG: exec launch_cmd with mapped env vars
AG-->>BF: ACP stdio session
|
| name = "codex-acp" | ||
| description = "OpenAI Codex agent via ACP" | ||
| install_cmd = "export DEBIAN_FRONTEND=noninteractive; BF_NODE_DIR=/opt/benchflow/node; BF_NODE_VERSION=22.20.0; if [ ! -x \"$BF_NODE_DIR/bin/node\" ]; then if ! command -v curl >/dev/null 2>&1 || ! command -v tar >/dev/null 2>&1 || ! command -v xz >/dev/null 2>&1; then if command -v apt-get >/dev/null 2>&1; then apt-get update -qq && apt-get install -y -qq curl ca-certificates tar xz-utils; elif command -v dnf >/dev/null 2>&1; then dnf -y install curl ca-certificates tar xz; elif command -v apk >/dev/null 2>&1; then apk add --no-cache curl ca-certificates tar xz; else echo 'BenchFlow JS agent bootstrap requires curl, tar, and xz' >&2; exit 127; fi; fi; arch=\"$(uname -m)\"; case \"$arch\" in x86_64|amd64) node_arch=x64 ;; aarch64|arm64) node_arch=arm64 ;; *) echo \"Unsupported architecture for Node.js: $arch\" >&2; exit 1 ;; esac; tmp=\"$(mktemp -d)\"; mkdir -p /opt/benchflow; curl -fsSLo \"$tmp/node.tar.xz\" \"https://nodejs.org/dist/v${BF_NODE_VERSION}/node-v${BF_NODE_VERSION}-linux-${node_arch}.tar.xz\"; rm -rf \"$BF_NODE_DIR\"; mkdir -p \"$BF_NODE_DIR\"; tar -xJf \"$tmp/node.tar.xz\" -C \"$BF_NODE_DIR\" --strip-components=1 --no-same-owner; rm -rf \"$tmp\"; fi; export PATH=\"/opt/benchflow/node/bin:$PATH\"; \"$BF_NODE_DIR/bin/node\" --version; \"$BF_NODE_DIR/bin/npm\" --version && mkdir -p /opt/benchflow/js-agents /opt/benchflow/bin && export PATH=\"/opt/benchflow/bin:/opt/benchflow/js-agents/bin:/opt/benchflow/node/bin:$PATH\" && ( /opt/benchflow/node/bin/npm install -g --prefix /opt/benchflow/js-agents @agentclientprotocol/codex-acp@0.0.45 ) && printf '%s\\n' '#!/bin/sh' 'exec /opt/benchflow/node/bin/node /opt/benchflow/js-agents/bin/codex-acp \"$@\"' > /opt/benchflow/bin/codex-acp && chmod +x /opt/benchflow/bin/codex-acp && chmod -R a+rX /opt/benchflow && [ -x /opt/benchflow/js-agents/bin/codex-acp ] && [ -x /opt/benchflow/bin/codex-acp ]" | ||
| launch_cmd = "h=\"${BENCHFLOW_AGENT_HOME:-$HOME}\"; if [ -n \"$OPENAI_API_KEY\" ]; then mkdir -p \"$h/.codex\" && printf '{\"OPENAI_API_KEY\": \"%s\"}' \"$OPENAI_API_KEY\" > \"$h/.codex/auth.json\"; fi; exec /opt/benchflow/bin/codex-acp ${OPENAI_BASE_URL:+-c openai_base_url=$OPENAI_BASE_URL}" |
There was a problem hiding this comment.
Unescaped API key in printf JSON construction
launch_cmd uses printf '{"OPENAI_API_KEY": "%s"}' "$OPENAI_API_KEY" to write auth.json. If OPENAI_API_KEY ever contains ", \, or a newline (e.g., a key passed in from a CI secret with trailing whitespace or embedded quotes), the resulting file is malformed JSON and codex will fail to authenticate. The same pattern appears in openhands/manifest.toml with LLM_MODEL and LLM_API_KEY. Consider piping through python3 -c "import json,sys,os; print(json.dumps({...}))" or similar for safe serialization.
| contract_version = "1.0" | ||
| name = "pi-acp" | ||
| description = "Pi agent via ACP" | ||
| install_cmd = "export DEBIAN_FRONTEND=noninteractive; BF_NODE_DIR=/opt/benchflow/node; BF_NODE_VERSION=22.20.0; if [ ! -x \"$BF_NODE_DIR/bin/node\" ]; then if ! command -v curl >/dev/null 2>&1 || ! command -v tar >/dev/null 2>&1 || ! command -v xz >/dev/null 2>&1; then if command -v apt-get >/dev/null 2>&1; then apt-get update -qq && apt-get install -y -qq curl ca-certificates tar xz-utils; elif command -v dnf >/dev/null 2>&1; then dnf -y install curl ca-certificates tar xz; elif command -v apk >/dev/null 2>&1; then apk add --no-cache curl ca-certificates tar xz; else echo 'BenchFlow JS agent bootstrap requires curl, tar, and xz' >&2; exit 127; fi; fi; arch=\"$(uname -m)\"; case \"$arch\" in x86_64|amd64) node_arch=x64 ;; aarch64|arm64) node_arch=arm64 ;; *) echo \"Unsupported architecture for Node.js: $arch\" >&2; exit 1 ;; esac; tmp=\"$(mktemp -d)\"; mkdir -p /opt/benchflow; curl -fsSLo \"$tmp/node.tar.xz\" \"https://nodejs.org/dist/v${BF_NODE_VERSION}/node-v${BF_NODE_VERSION}-linux-${node_arch}.tar.xz\"; rm -rf \"$BF_NODE_DIR\"; mkdir -p \"$BF_NODE_DIR\"; tar -xJf \"$tmp/node.tar.xz\" -C \"$BF_NODE_DIR\" --strip-components=1 --no-same-owner; rm -rf \"$tmp\"; fi; export PATH=\"/opt/benchflow/node/bin:$PATH\"; \"$BF_NODE_DIR/bin/node\" --version; \"$BF_NODE_DIR/bin/npm\" --version && mkdir -p /opt/benchflow/js-agents /opt/benchflow/bin && export PATH=\"/opt/benchflow/bin:/opt/benchflow/js-agents/bin:/opt/benchflow/node/bin:$PATH\" && ( [ -x /opt/benchflow/js-agents/bin/pi ] || /opt/benchflow/node/bin/npm install -g --prefix /opt/benchflow/js-agents @mariozechner/pi-coding-agent@latest ) && printf '%s\\n' '#!/bin/sh' 'exec /opt/benchflow/node/bin/node /opt/benchflow/js-agents/bin/pi \"$@\"' > /opt/benchflow/bin/pi && chmod +x /opt/benchflow/bin/pi && chmod -R a+rX /opt/benchflow && [ -x /opt/benchflow/js-agents/bin/pi ] && [ -x /opt/benchflow/bin/pi ] && export DEBIAN_FRONTEND=noninteractive; BF_NODE_DIR=/opt/benchflow/node; BF_NODE_VERSION=22.20.0; if [ ! -x \"$BF_NODE_DIR/bin/node\" ]; then if ! command -v curl >/dev/null 2>&1 || ! command -v tar >/dev/null 2>&1 || ! command -v xz >/dev/null 2>&1; then if command -v apt-get >/dev/null 2>&1; then apt-get update -qq && apt-get install -y -qq curl ca-certificates tar xz-utils; elif command -v dnf >/dev/null 2>&1; then dnf -y install curl ca-certificates tar xz; elif command -v apk >/dev/null 2>&1; then apk add --no-cache curl ca-certificates tar xz; else echo 'BenchFlow JS agent bootstrap requires curl, tar, and xz' >&2; exit 127; fi; fi; arch=\"$(uname -m)\"; case \"$arch\" in x86_64|amd64) node_arch=x64 ;; aarch64|arm64) node_arch=arm64 ;; *) echo \"Unsupported architecture for Node.js: $arch\" >&2; exit 1 ;; esac; tmp=\"$(mktemp -d)\"; mkdir -p /opt/benchflow; curl -fsSLo \"$tmp/node.tar.xz\" \"https://nodejs.org/dist/v${BF_NODE_VERSION}/node-v${BF_NODE_VERSION}-linux-${node_arch}.tar.xz\"; rm -rf \"$BF_NODE_DIR\"; mkdir -p \"$BF_NODE_DIR\"; tar -xJf \"$tmp/node.tar.xz\" -C \"$BF_NODE_DIR\" --strip-components=1 --no-same-owner; rm -rf \"$tmp\"; fi; export PATH=\"/opt/benchflow/node/bin:$PATH\"; \"$BF_NODE_DIR/bin/node\" --version; \"$BF_NODE_DIR/bin/npm\" --version && mkdir -p /opt/benchflow/js-agents /opt/benchflow/bin && export PATH=\"/opt/benchflow/bin:/opt/benchflow/js-agents/bin:/opt/benchflow/node/bin:$PATH\" && ( [ -x /opt/benchflow/js-agents/bin/pi-acp ] || /opt/benchflow/node/bin/npm install -g --prefix /opt/benchflow/js-agents pi-acp@latest ) && printf '%s\\n' '#!/bin/sh' 'exec /opt/benchflow/node/bin/node /opt/benchflow/js-agents/bin/pi-acp \"$@\"' > /opt/benchflow/bin/pi-acp && chmod +x /opt/benchflow/bin/pi-acp && chmod -R a+rX /opt/benchflow && [ -x /opt/benchflow/js-agents/bin/pi-acp ] && [ -x /opt/benchflow/bin/pi-acp ] && ( command -v python3 >/dev/null 2>&1 || (apt-get update -qq && apt-get install -y -qq python3 >/dev/null 2>&1) ) && mkdir -p /opt/benchflow/bin && echo IyEvdXNyL2Jpbi9lbnYgcHl0aG9uMwoiIiJMYXVuY2ggd3JhcHBlciBmb3IgcGktYWNwIOKAlCBicmlkZ2VzIEJFTkNIRkxPV19QUk9WSURFUl8qIHRvIFBpIGNvbmZpZy4KClBpIG5hdGl2ZWx5IHJlYWRzIEFOVEhST1BJQ18qIGVudiB2YXJzIGZvciBBbnRocm9waWMgcHJvdmlkZXJzLiBGb3IKT3BlbkFJLWNvbXBhdGlibGUgcHJvdmlkZXJzICh2TExNLCBldGMuKSwgUGkgcmVxdWlyZXMgYSBgYG1vZGVscy5qc29uYGAKY29uZmlnIGZpbGUgYXQgYGB+Ly5waS9hZ2VudC9tb2RlbHMuanNvbmBgIHRoYXQgZGVjbGFyZXMgdGhlIHByb3ZpZGVyJ3MKd2lyZSBwcm90b2NvbC4gIFRoaXMgd3JhcHBlciBnZW5lcmF0ZXMgaXQgZnJvbSBCRU5DSEZMT1dfUFJPVklERVJfKiBlbnYKdmFycyBpbmplY3RlZCBieSB0aGUgU0RLLCB0aGVuIGV4ZWNzIGBgcGktYWNwYGAuCgpTZWUgaHR0cHM6Ly9naXRodWIuY29tL2JhZGxvZ2ljL3BpLW1vbm8vYmxvYi9tYWluL3BhY2thZ2VzL2NvZGluZy1hZ2VudC9kb2NzL21vZGVscy5tZAoiIiIKCmltcG9ydCBqc29uCmltcG9ydCBvcwppbXBvcnQgc3lzCmZyb20gcGF0aGxpYiBpbXBvcnQgUGF0aAoKIyBQaSBtb2RlbC1tZXRhZGF0YSBkZWZhdWx0cyBpZiBuZWl0aGVyIHRoZSBwcm92aWRlciByZWdpc3RyeSBub3IgcGVyLXJ1bgojIG92ZXJyaWRlcyBzdXBwbHkgdmFsdWVzLiBDb25zZXJ2YXRpdmUg4oCUIG1vc3QgbW9kZXJuIG1vZGVscyBleGNlZWQgdGhlc2UuCl9ERUZBVUxUX0NPTlRFWFRfV0lORE9XID0gMTI4MDAwCl9ERUZBVUxUX01BWF9UT0tFTlMgPSAxNjM4NApfQkVOQ0hGTE9XX0JJTl9ESVIgPSAiL29wdC9iZW5jaGZsb3cvYmluIgpfUElfQUNQX0JJTiA9ICIvb3B0L2JlbmNoZmxvdy9iaW4vcGktYWNwIgoKCmRlZiBfbG9va3VwX21vZGVsX21ldGFkYXRhKG1vZGVsOiBzdHIpIC0+IGRpY3Q6CiAgICAiIiJSZXR1cm4gdGhlIHJlZ2lzdHJ5IGVudHJ5IGZvciBgbW9kZWxgIGZyb20gQkVOQ0hGTE9XX1BST1ZJREVSX01PREVMUywgb3Ige30uIiIiCiAgICByYXcgPSBvcy5lbnZpcm9uLmdldCgiQkVOQ0hGTE9XX1BST1ZJREVSX01PREVMUyIsICIiKQogICAgaWYgbm90IHJhdzoKICAgICAgICByZXR1cm4ge30KICAgIHRyeToKICAgICAgICBlbnRyaWVzID0ganNvbi5sb2FkcyhyYXcpCiAgICBleGNlcHQganNvbi5KU09ORGVjb2RlRXJyb3I6CiAgICAgICAgcmV0dXJuIHt9CiAgICBmb3IgZW50cnkgaW4gZW50cmllczoKICAgICAgICBpZiBpc2luc3RhbmNlKGVudHJ5LCBkaWN0KSBhbmQgZW50cnkuZ2V0KCJpZCIpID09IG1vZGVsOgogICAgICAgICAgICByZXR1cm4gZW50cnkKICAgIHJldHVybiB7fQoKCmRlZiBfZGVyaXZlX3Byb3ZpZGVyX25hbWUobW9kZWw6IHN0cikgLT4gc3RyOgogICAgIiIiRGVyaXZlIGEgdW5pcXVlIHByb3ZpZGVyIGtleSBzbyBjb25jdXJyZW50IHJ1bnMgZG9uJ3QgY29sbGlkZSBvbiAiY3VzdG9tIi4iIiIKICAgIGlmICIvIiBpbiBtb2RlbDoKICAgICAgICByZXR1cm4gZiJiZW5jaGZsb3cte21vZGVsLnNwbGl0KCcvJylbMF19IgogICAgcmV0dXJuIGYiYmVuY2hmbG93LXttb2RlbH0iIGlmIG1vZGVsIGVsc2UgImJlbmNoZmxvdy1jdXN0b20iCgoKZGVmIHNldHVwX3Byb3ZpZGVyKCkgLT4gTm9uZToKICAgICIiIkNvbmZpZ3VyZSBQaSBmb3IgdGhlIGRldGVjdGVkIHByb3ZpZGVyIHByb3RvY29sLiIiIgogICAgcHJvdG9jb2wgPSBvcy5lbnZpcm9uLmdldCgiQkVOQ0hGTE9XX1BST1ZJREVSX1BST1RPQ09MIiwgIiIpCiAgICBiYXNlX3VybCA9IG9zLmVudmlyb24uZ2V0KCJCRU5DSEZMT1dfUFJPVklERVJfQkFTRV9VUkwiLCAiIikKICAgIGFwaV9rZXkgPSBvcy5lbnZpcm9uLmdldCgiQkVOQ0hGTE9XX1BST1ZJREVSX0FQSV9LRVkiLCAiIikKICAgIG1vZGVsID0gb3MuZW52aXJvbi5nZXQoIkJFTkNIRkxPV19QUk9WSURFUl9NT0RFTCIsICIiKQogICAgcHJvdmlkZXJfbmFtZSA9IG9zLmVudmlyb24uZ2V0KCJCRU5DSEZMT1dfUFJPVklERVJfTkFNRSIpIG9yIF9kZXJpdmVfcHJvdmlkZXJfbmFtZSgKICAgICAgICBtb2RlbAogICAgKQoKICAgIGlmIHByb3RvY29sID09ICJvcGVuYWktY29tcGxldGlvbnMiOgogICAgICAgIGlmIG5vdCBiYXNlX3VybDoKICAgICAgICAgICAgcmFpc2UgU3lzdGVtRXhpdCgKICAgICAgICAgICAgICAgICJwaS1hY3A6IEJFTkNIRkxPV19QUk9WSURFUl9QUk9UT0NPTD1vcGVuYWktY29tcGxldGlvbnMgcmVxdWlyZXMgIgogICAgICAgICAgICAgICAgIkJFTkNIRkxPV19QUk9WSURFUl9CQVNFX1VSTCwgYnV0IGl0IGlzIGVtcHR5LiBDaGVjayBwcm92aWRlciAiCiAgICAgICAgICAgICAgICAicmVnaXN0cnkgdXJsX3BhcmFtcyAoZS5nLiBtaXNzaW5nIEdPT0dMRV9DTE9VRF9QUk9KRUNUKS4iCiAgICAgICAgICAgICkKICAgICAgICAjIFBpIHVzZXMgfi8ucGkvYWdlbnQvbW9kZWxzLmpzb24gdG8gZGlzY292ZXIgbm9uLUFudGhyb3BpYyBwcm92aWRlcnMuCiAgICAgICAgIyBSZWdpc3RlciB0aGUgcHJvdmlkZXIgc28gUGkgcm91dGVzIEFQSSBjYWxscyB0aHJvdWdoIHRoZSBPcGVuQUkKICAgICAgICAjIENoYXQgQ29tcGxldGlvbnMgd2lyZSBmb3JtYXQgaW5zdGVhZCBvZiBBbnRocm9waWMgTWVzc2FnZXMuCiAgICAgICAgbWV0YSA9IF9sb29rdXBfbW9kZWxfbWV0YWRhdGEobW9kZWwpCiAgICAgICAgY29uZmlnID0gewogICAgICAgICAgICAicHJvdmlkZXJzIjogewogICAgICAgICAgICAgICAgcHJvdmlkZXJfbmFtZTogewogICAgICAgICAgICAgICAgICAgICJiYXNlVXJsIjogYmFzZV91cmwsCiAgICAgICAgICAgICAgICAgICAgImFwaSI6ICJvcGVuYWktY29tcGxldGlvbnMiLAogICAgICAgICAgICAgICAgICAgICJhcGlLZXkiOiBhcGlfa2V5IG9yICJ1bnVzZWQiLAogICAgICAgICAgICAgICAgICAgICJtb2RlbHMiOiBbCiAgICAgICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJpZCI6IG1vZGVsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIm5hbWUiOiBtZXRhLmdldCgibmFtZSIsIG1vZGVsKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJyZWFzb25pbmciOiBtZXRhLmdldCgicmVhc29uaW5nIiwgRmFsc2UpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgImlucHV0IjogbWV0YS5nZXQoImlucHV0IiwgWyJ0ZXh0Il0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbnRleHRXaW5kb3ciOiBtZXRhLmdldCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29udGV4dFdpbmRvdyIsIF9ERUZBVUxUX0NPTlRFWFRfV0lORE9XCiAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIm1heFRva2VucyI6IG1ldGEuZ2V0KCJtYXhUb2tlbnMiLCBfREVGQVVMVF9NQVhfVE9LRU5TKSwKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgY29uZmlnX2RpciA9IFBhdGguaG9tZSgpIC8gIi5waSIgLyAiYWdlbnQiCiAgICAgICAgY29uZmlnX2Rpci5ta2RpcihwYXJlbnRzPVRydWUsIGV4aXN0X29rPVRydWUpCiAgICAgICAgbW9kZWxzX3BhdGggPSBjb25maWdfZGlyIC8gIm1vZGVscy5qc29uIgogICAgICAgICMgTWVyZ2Ugd2l0aCBleGlzdGluZyBjb25maWcgc28gbWFudWFsbHktYWRkZWQgcHJvdmlkZXJzIHN1cnZpdmUKICAgICAgICBpZiBtb2RlbHNfcGF0aC5leGlzdHMoKToKICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgZXhpc3RpbmcgPSBqc29uLmxvYWRzKG1vZGVsc19wYXRoLnJlYWRfdGV4dCgpKQogICAgICAgICAgICAgICAgZXhpc3Rpbmcuc2V0ZGVmYXVsdCgicHJvdmlkZXJzIiwge30pLnVwZGF0ZShjb25maWdbInByb3ZpZGVycyJdKQogICAgICAgICAgICAgICAgY29uZmlnID0gZXhpc3RpbmcKICAgICAgICAgICAgZXhjZXB0IChqc29uLkpTT05EZWNvZGVFcnJvciwgT1NFcnJvcik6CiAgICAgICAgICAgICAgICBwcmludCgKICAgICAgICAgICAgICAgICAgICBmIldhcm5pbmc6IGNvdWxkIG5vdCBwYXJzZSB7bW9kZWxzX3BhdGh9LCBvdmVyd3JpdGluZy4iLAogICAgICAgICAgICAgICAgICAgIGZpbGU9c3lzLnN0ZGVyciwKICAgICAgICAgICAgICAgICkKICAgICAgICBtb2RlbHNfcGF0aC53cml0ZV90ZXh0KGpzb24uZHVtcHMoY29uZmlnLCBpbmRlbnQ9MikpCiAgICBlbHNlOgogICAgICAgICMgQW50aHJvcGljIG1vZGUg4oCUIHNldCBuYXRpdmUgZW52IHZhcnMgdGhhdCBQaSByZWFkcyBkaXJlY3RseS4KICAgICAgICAjIERPIE5PVCBjaGFuZ2Ugc2V0ZGVmYXVsdCB0byBhc3NpZ25tZW50LiBVc2VycyByb3V0ZSB0aHJvdWdoIHByb3hpZXMKICAgICAgICAjIHdpdGggLS1hZ2VudC1lbnYgQU5USFJPUElDX0JBU0VfVVJMPTxwcm94eT47IG92ZXJ3cml0aW5nIGJyZWFrcyB0aGF0IHBhdGguCiAgICAgICAgIyBXaHk6IEJFTkNIRkxPV19QUk9WSURFUl9CQVNFX1VSTCBpcyB0aGUgcmVnaXN0cnkgZGVmYXVsdDsgdGhlIHVzZXIncwogICAgICAgICMgLS1hZ2VudC1lbnYgb3ZlcnJpZGUgbXVzdCB3aW4uIFBpbm5lZCBieSB0ZXN0cy90ZXN0X3BpX2FjcF9sYXVuY2hlci5weTo6CiAgICAgICAgIyB0ZXN0X3NldGRlZmF1bHRfZG9lc19ub3Rfb3ZlcndyaXRlLgogICAgICAgIGlmIGJhc2VfdXJsOgogICAgICAgICAgICBvcy5lbnZpcm9uLnNldGRlZmF1bHQoIkFOVEhST1BJQ19CQVNFX1VSTCIsIGJhc2VfdXJsKQogICAgICAgIGlmIGFwaV9rZXk6CiAgICAgICAgICAgIG9zLmVudmlyb24uc2V0ZGVmYXVsdCgiQU5USFJPUElDX0FVVEhfVE9LRU4iLCBhcGlfa2V5KQogICAgICAgIGlmIG1vZGVsOgogICAgICAgICAgICBvcy5lbnZpcm9uLnNldGRlZmF1bHQoIkFOVEhST1BJQ19NT0RFTCIsIG1vZGVsKQoKCmRlZiBfcHJlcGVuZF9iZW5jaGZsb3dfYmluX3BhdGgoKSAtPiBOb25lOgogICAgIiIiTGV0IHBpLWFjcCBmaW5kIHRoZSBwYWlyZWQgcGkgd3JhcHBlciB3aXRob3V0IGV4cG9zaW5nIE5vZGUvbnBtLiIiIgogICAgY3VycmVudCA9IG9zLmVudmlyb24uZ2V0KCJQQVRIIiwgIiIpCiAgICBwYXJ0cyA9IGN1cnJlbnQuc3BsaXQoIjoiKSBpZiBjdXJyZW50IGVsc2UgW10KICAgIGlmIF9CRU5DSEZMT1dfQklOX0RJUiBub3QgaW4gcGFydHM6CiAgICAgICAgb3MuZW52aXJvblsiUEFUSCJdID0gKAogICAgICAgICAgICBmIntfQkVOQ0hGTE9XX0JJTl9ESVJ9OntjdXJyZW50fSIgaWYgY3VycmVudCBlbHNlIF9CRU5DSEZMT1dfQklOX0RJUgogICAgICAgICkKCgpkZWYgbWFpbigpIC0+IE5vbmU6CiAgICBzZXR1cF9wcm92aWRlcigpCiAgICBfcHJlcGVuZF9iZW5jaGZsb3dfYmluX3BhdGgoKQogICAgdHJ5OgogICAgICAgIG9zLmV4ZWN2KF9QSV9BQ1BfQklOLCBbX1BJX0FDUF9CSU4sICpzeXMuYXJndlsxOl1dKQogICAgZXhjZXB0IEZpbGVOb3RGb3VuZEVycm9yIGFzIGU6CiAgICAgICAgcmFpc2UgU3lzdGVtRXhpdCgKICAgICAgICAgICAgZiJwaS1hY3A6IHtfUElfQUNQX0JJTiFyfSBub3QgZm91bmQuIEl0IHNob3VsZCBoYXZlIGJlZW4gIgogICAgICAgICAgICAiaW5zdGFsbGVkIGJ5IHRoZSByZWdpc3RyeSdzIGluc3RhbGxfY21kIHZpYSAiCiAgICAgICAgICAgICInbnBtIGluc3RhbGwgLWcgcGktYWNwJy4gQ2hlY2sgdGhlIGNvbnRhaW5lcidzIGluc3RhbGwgbG9nLiIKICAgICAgICApIGZyb20gZQoKCmlmIF9fbmFtZV9fID09ICJfX21haW5fXyI6CiAgICBtYWluKCkK | base64 -d > /opt/benchflow/bin/pi-acp-launcher && chmod +x /opt/benchflow/bin/pi-acp-launcher" |
There was a problem hiding this comment.
Entire Node.js bootstrap block duplicated in install_cmd
The install_cmd contains the full Node.js download-and-install bootstrap (the if [ ! -x "$BF_NODE_DIR/bin/node" ]; then … fi block) twice — once before installing @mariozechner/pi-coding-agent and again verbatim before installing pi-acp. The second occurrence is a no-op at runtime (the node binary is already present), but it roughly doubles the manifest size and makes the command harder to audit. Consider factoring the bootstrap into a shared variable or a helper, or omitting the repeated copy.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
What
The 8 core-derived ACP agent manifests that benchflow's manifest loader (
load_agent_manifest, merged in #14) consumes — the agents-side half of the decouple "running-through" path. Eachmanifest.tomlis the data-only projection of a coreAGENTSentry; benchflow merges it with that entry's host-side shim-only fields (subscription_auth,credential_files, …) so a manifest-loaded agent == the original core agent.Agents:
claude-agent-acp, codex-acp, gemini, mimo, openclaw, opencode, openhands, pi-acp.How it fits
BENCHFLOW_AGENTS_DIRpoints at this tree — see feat(agents): all-paths decouple core — manifest loader (8 ACP) + omnigent session-factory seam (additive, gated) benchflow#825 (the core consumer loader + additive merge-mode). Additive / gated: no effect on benchflow's built-inAGENTSunless that env is set (strangler-fig).codex-acpships the self-writing launcher (c675b3d): writes~/.codex/auth.jsonfromOPENAI_API_KEYonly when the key is set, leaving ChatGPT-subscription mode (hostauth.json) untouched. Pairs with the benchflow-core subscription fix in feat(agents): all-paths decouple core — manifest loader (8 ACP) + omnigent session-factory seam (additive, gated) benchflow#825.Verified — e2e citation-check, both docker + daytona
All 8 load from these manifests, and the shim-only merge
== origcore entry on every dataclass field. End-to-end via benchflow#825:Test plan
== origfor all 8 (benchflow loader tests).BENCHFLOW_AGENTS_DIR.