Version
codebase-memory-mcp 0.10.5
Platform
Linux (x64)
Install channel
GitHub release archive / install.sh / install.ps1
Binary variant
standard
What happened, and what did you expect?
The one-line installer against a working goose setup fails deterministically at the Goose step, while every other agent (Claude Code, JSON) configures successfully in the same run:
error: agent_config agent=Goose op=mcp_install path=/home/<user>/.config/goose/config.yaml (target: regular file, 4202 bytes)
error: one or more agent configurations failed; the published/current executable was kept, and PATH/index cleanup was not attempted
Expected: the installer appends its codebase-memory-mcp entry under the existing extensions: mapping. Constructs in sibling entries that the editor never touches should not veto the write.
Root cause (verified against main today)
Goose serializes every stdio extension with envs: {} — e.g. an extension goose itself configured looks like:
extensions:
linux-mcp-server:
enabled: true
type: stdio
name: linux-mcp-server
cmd: uvx
args:
- --python
- '3.13'
- linux-mcp-server
envs: {}
env_keys: []
timeout: 300
cbm_upsert_goose_mcp (src/cli/cli.c:3762) → cbm_upsert_yaml_stdio_mcp(..., "extensions", ...) → cbm_yaml_upsert_owned_mapping_entry → yaml_analyze_mapping → yaml_validate_mapping_body, which calls yaml_range_has_unsupported on every body line of the target section (src/cli/config_yaml_edit.c:1407). That check rejects any unquoted { or }:
/* src/cli/config_yaml_edit.c:1271, yaml_range_has_unsupported */
if (c == '{' || c == '}') {
return YAML_MATCH; /* caller treats as YAML_ERROR */
}
So any goose config containing at least one stdio extension that goose itself wrote is uneditable by the installer. Flow sequences are fine (args: [] passes — the canonical CBM entry installs cleanly on an otherwise-empty section), which isolates this to flow mappings.
Consequences worth noting:
Bisect evidence (sandboxed $HOME, so the real config was never at risk)
| Config shape |
Result |
Real goose config (4 stdio extensions with envs: {}) |
FAIL |
| Same, all stdio extensions removed |
OK |
Minimal single-entry config with envs: {} (repro below) |
FAIL |
Identical minus the one envs: {} line |
OK |
Block-style args: converted to flow style args: ["-c", ...] |
still FAIL |
cwd: null / bundled: null lines removed |
still FAIL |
| Canonical CBM entry pre-inserted alongside the stdio entry |
still FAIL |
Workaround (verified end-to-end on 0.10.5)
Delete the envs: {} lines (semantically identical for goose — an absent envs key deserializes to an empty env map), then re-run the installer; it completes, writes the entry, and the server passes a stdio MCP handshake. Caveat: goose will re-serialize envs: {} the next time it rewrites config.yaml (e.g. via goose configure), so this recurs on every future codebase-memory-mcp update until fixed.
Suggested fix direction
The editor only upserts its own entry under extensions: — it does not need to interpret flow mappings inside sibling entries' values. #1639 already established the precedent for this class of fix (interior */& treated as text rather than anchors). Alternatively/additionally, carrying the refusal reason out instead of collapsing to -1 (as #1630 asks, and as cbm_daemon_ipc_validation_detail() already does) would have made this a one-minute diagnosis.
Reproduction
No indexing or real code involved — this is a pure installer/config-editor bug, and the repro uses only dummy content.
- Config: a minimal fake goose home containing one stdio extension with the
envs: {} line goose itself writes:
CBM="$(command -v codebase-memory-mcp)" # real binary location
mkdir -p "$HOME/cbm-repro/.config/goose"
cat > "$HOME/cbm-repro/.config/goose/config.yaml" <<'EOF'
GOOSE_TELEMETRY_ENABLED: true
extensions:
demo:
enabled: true
type: stdio
cmd: /bin/true
args:
- --serve
envs: {}
env_keys: []
timeout: 300
GOOSE_THINKING_EFFORT: max
EOF
- Command (Goose detection triggers via the
~/.config/goose directory; $HOME override sandboxes everything else):
HOME="$HOME/cbm-repro" "$CBM" install -y --force --dir="$(dirname "$CBM")"
-
Result: error: agent_config agent=Goose op=mcp_install ... and activation aborts (non-zero exit).
-
Expected: install completes. Proof that the single envs: {} line is the entire trigger:
sed -i '/^ envs: {}$/d' "$HOME/cbm-repro/.config/goose/config.yaml"
HOME="$HOME/cbm-repro" "$CBM" install -y --force --dir="$(dirname "$CBM")"
# → "Install complete."
Both directions verified today on 0.10.5, Linux x86_64.
Logs
codebase-memory-mcp installer
os: linux
arch: amd64
Stopping active CBM sessions and operations for install...
error: agent_config agent=Goose op=mcp_install path=/home/<user>/.config/goose/config.yaml (target: regular file, 4202 bytes)
error: one or more agent configurations failed; the published/current executable was kept, and PATH/index cleanup was not attempted
error: activation stopped after one or more agent configuration or cleanup operations failed; the published/current executable was kept, and configuration changes that completed may remain. Please restart your coding-agent sessions after resolving the errors above.
Detected agents: Claude-Code Goose
Diagnostics trajectory (memory / performance / leak issues)
Project scale (if relevant)
No response
Confirmations
Version
codebase-memory-mcp 0.10.5
Platform
Linux (x64)
Install channel
GitHub release archive / install.sh / install.ps1
Binary variant
standard
What happened, and what did you expect?
The one-line installer against a working goose setup fails deterministically at the Goose step, while every other agent (Claude Code, JSON) configures successfully in the same run:
Expected: the installer appends its
codebase-memory-mcpentry under the existingextensions:mapping. Constructs in sibling entries that the editor never touches should not veto the write.Root cause (verified against
maintoday)Goose serializes every stdio extension with
envs: {}— e.g. an extension goose itself configured looks like:cbm_upsert_goose_mcp(src/cli/cli.c:3762) →cbm_upsert_yaml_stdio_mcp(..., "extensions", ...)→cbm_yaml_upsert_owned_mapping_entry→yaml_analyze_mapping→yaml_validate_mapping_body, which callsyaml_range_has_unsupportedon every body line of the target section (src/cli/config_yaml_edit.c:1407). That check rejects any unquoted{or}:So any goose config containing at least one stdio extension that goose itself wrote is uneditable by the installer. Flow sequences are fine (
args: []passes — the canonical CBM entry installs cleanly on an otherwise-empty section), which isolates this to flow mappings.Consequences worth noting:
~/.config/goose/yaml) #728 (the Goose support request) literally includesenvs: {}, so a freshgoose configure-generated config will hit this immediately.config.yamlrefusal) may be the same editor refusing a real-world file; this report pins one concrete, reproducible trigger for the shared code path.Bisect evidence (sandboxed
$HOME, so the real config was never at risk)envs: {})envs: {}(repro below)envs: {}lineargs:converted to flow styleargs: ["-c", ...]cwd: null/bundled: nulllines removedWorkaround (verified end-to-end on 0.10.5)
Delete the
envs: {}lines (semantically identical for goose — an absentenvskey deserializes to an empty env map), then re-run the installer; it completes, writes the entry, and the server passes a stdio MCP handshake. Caveat: goose will re-serializeenvs: {}the next time it rewritesconfig.yaml(e.g. viagoose configure), so this recurs on every futurecodebase-memory-mcp updateuntil fixed.Suggested fix direction
The editor only upserts its own entry under
extensions:— it does not need to interpret flow mappings inside sibling entries' values. #1639 already established the precedent for this class of fix (interior*/&treated as text rather than anchors). Alternatively/additionally, carrying the refusal reason out instead of collapsing to-1(as #1630 asks, and ascbm_daemon_ipc_validation_detail()already does) would have made this a one-minute diagnosis.Reproduction
No indexing or real code involved — this is a pure installer/config-editor bug, and the repro uses only dummy content.
envs: {}line goose itself writes:~/.config/goosedirectory;$HOMEoverride sandboxes everything else):Result:
error: agent_config agent=Goose op=mcp_install ...and activation aborts (non-zero exit).Expected: install completes. Proof that the single
envs: {}line is the entire trigger:Both directions verified today on 0.10.5, Linux x86_64.
Logs
Diagnostics trajectory (memory / performance / leak issues)
Project scale (if relevant)
No response
Confirmations