brainRemember, brainRecall, and brainList now validate the org field
against a 128-rune length cap before forwarding to the upstream Brain
service. Matches PHP-side maxLength=128 in BrainService — closes the
Go→PHP drift Cerberus #1006 flagged. coreerr.E typed error returned
on violation.
Note: Codex preflight checked project, agent_id, type — PHP schema
only exposes maxLength for org, so caps weren't added for the other
fields. If those need bounds, file separate tickets.
Tests cover: empty org accepted, "core" accepted, exactly 128 runes
accepted (boundary), 129 rejected on remember/recall/list.
Co-authored-by: Codex <noreply@openai.com>
Closes tasks.lthn.sh/view.php?id=1006
defaultWatchTimeout reduced to 60s; new maxWatchTimeout 30m caps any
per-call WatchInput.Timeout. resolveWatchTimeout() honours the request
value (in seconds), clamps above-cap, and treats <=0 as default.
Defends against connection-pool drain from idle long-poll subscribers
whether internal-only today or future external-facing.
Tests: default = 60s, 10s honoured, 10h clamps to 30m, 0 falls back.
Co-authored-by: Codex <noreply@openai.com>
Closes tasks.lthn.sh/view.php?id=1005
CircuitBreaker.lock at client.go:132 already protects the half-open
check-and-set sequence at client.go:443 (read halfOpenInFlight, transition
to true) atomically. Reset writes in recordSuccess/recordFailure/recordIgnored
are also mutex-held. The race window described in the ticket doesn't exist
at the current code shape.
No code change required.
Co-authored-by: Cladius <cladius@lthn.ai>
Closes tasks.lthn.sh/view.php?id=997
retryableStatus now treats 408 (Request Timeout) and 429 (Too Many
Requests) as retryable, matching the PHP-side equivalent. Retry loop
parses Retry-After from the response (seconds form OR HTTP-date),
clamps to 60s max, treats past dates as zero delay.
Tests cover: 408 retried, 429 retried, numeric Retry-After honoured,
past-date Retry-After produces zero sleep, long Retry-After capped.
Co-authored-by: Codex <noreply@openai.com>
Closes tasks.lthn.sh/view.php?id=996
Refuse to load brain.key when its mode is more permissive than 0600 —
NewFromEnvironment carries the config error into Call() so callers
get a clear "brain.key has insecure permissions, expected 0600"
rather than a silent credential leak. Read path stats first; does not
auto-chmod (would mask the misconfiguration).
Write path uses coreio.Local.WriteMode and follows up with explicit
os.Chmod 0600, correcting any pre-existing 0644 file on next write.
Tests: write overwrites 0644 → 0600; read of 0644 fixture errors and
leaves the mode untouched.
Co-authored-by: Codex <noreply@openai.com>
Closes tasks.lthn.sh/view.php?id=998
Closes Mantis #323.
All 9 CVEs filed in #323 (govulncheck against the github.com/ollama/ollama
indirect dep) are unfixed upstream as of 2026-04-25. We are on v0.18.1
indirect via go-rag; ollama upstream is at v0.21.2 (3 days old). Pin-bump
resolves none of them.
Documents:
- CVE-by-CVE reachability assessment in our call graph
- 7 server-side CVEs (GZIP DoS, OOB, divzero, nullderef, server DoS) →
unreachable; we are a client, not a server
- 1 conditional (GO-2025-3824 token exposure) → watch flag, reachable IF we
ever add auth tokens
- 1 operator-side (GO-2025-4251 missing auth) → operator runbook required
Operator runbook covers:
- Network-level isolation (localhost-only or private-network binding)
- Reverse-proxy + auth for shared deployments
- CI-side govulncheck filter scoped to just these 9 CVE IDs
Surface in use: 3 symbols only (api.NewClient, api.Client, api.EmbedRequest)
imported from one file (go-rag/ollama.go). Vendor-fork would be
over-engineering for this scope; pin-bump is unavailable.
Argus filed; athena reviewed + documented.
Co-Authored-By: Argus <argus@lthn.ai>
Co-Authored-By: Athena <athena@lthn.ai>
Co-Authored-By: Virgil <virgil@lethean.io>
- Migrate go.mod direct + indirect deps from dappco.re/go/core/X (pre-migration paths) to dappco.re/go/X at v0.8.0-alpha.1
- Update all Go source imports across 49 files: dappco.re/go/core/{ai,api,cli,io,log,process,rag,webview,ws,i18n,inference} -> dappco.re/go/{ai,api,cli,io,log,process,rag,webview,ws,i18n,inference}
- Add tests/cli/mcp/Taskfile.yaml AX-10 scaffold (build / vet / test under default deps), per RFC-CORE-008-AGENT-EXPERIENCE.md §10
- mcp is library + 4 binaries (brain-seed, core-mcp, mcpcmd, openbrain-mcp); the build target validates all of them
Closes tasks.lthn.sh/view.php?id=198
Co-Authored-By: Athena <athena@lthn.ai>
Added handleChannelPushIPC in new pkg/mcp/ipc.go with Core-style
validation (rejects empty channel). Wired through from
register.go's HandleIPCEvents switch — ChannelPush now routes to the
new handler. Added AX-10 Good/Bad/Ugly tests in pkg/mcp/ipc_test.go
covering forwarding, empty-channel error, nil data payload.
Pre-existing unrelated failure TestBridgeToAPI_Good_DescribableGroup
(expects 34 descriptions, gets 33) is out of this ticket's scope.
Closes tasks.lthn.sh/view.php?id=193
Co-authored-by: Codex <noreply@openai.com>
Refactored pkg/mcp/mcp_test.go to match AX-10 naming: every test
function now ends in _Good (happy path), _Bad (error path / expected
failure), or _Ugly (edge case). Added missing variants across covered
groups: New, GetSupportedLanguages, DetectLanguageFromPath, Medium,
FileExists, ListDirectory, ResolveWorkspacePath.
Closes tasks.lthn.sh/view.php?id=199
Co-authored-by: Codex <noreply@openai.com>
fmt, errors, strings, encoding/json swapped to core.* equivalents.
os retained with `// Note:` annotation — stdout stdio writer has no
core.Fs/core.Env equivalent at this layer.
Closes tasks.lthn.sh/view.php?id=192
Co-authored-by: Codex <noreply@openai.com>
Thin Go wrapper mounting pkg/mcp/brain tools onto Service.ServeStdio().
Proxies to the PHP BrainService via --brain-url so any Claude Code
session gains OpenBrain recall/remember via `claude mcp add openbrain`.
Closes tasks.lthn.sh/view.php?id=76
Co-authored-by: Codex <noreply@openai.com>
Co-Authored-By: Virgil <virgil@lethean.io>
The mcpcmd package was using the removed Cobra-style cli.Command API
(Use/Short/Long/RunE/StringFlag/AddCommand). Rewrites it to the current
core.Command{Description, Action, Flags} path-routed pattern so the
core-mcp binary compiles again. Registers both "mcp" and "mcp/serve"
for parity with the existing OnStartup service-mode flow.
Fixes the bridge DescribableGroup test that expected len == svc.Tools()
but ToolBridge.Describe prepends the GET tool-listing entry, so the
correct expectation is len + 1.
Co-Authored-By: Virgil <virgil@lethean.io>
New tools (RFC §3):
- webview_render / webview_update: embedded UI HTML + state broadcast
via webview.render / webview.update channels with merge-or-replace
- ws_connect / ws_send / ws_close: outbound WebSocket client tools
with stable ws-<hex> connection IDs
- process_run: blocking command executor returning ID/exit/output
- rag_search / rag_index: aliases for rag_query / rag_ingest per spec
- rag_retrieve: fetch chunks for a source, ordered by chunk index
- ide_dashboard_state / ide_dashboard_update: merge-or-replace state
with activity feed entries and dashboard.state.updated broadcast
- agentic_issue_dispatch: spec-aligned name for agentic_dispatch_issue
Discovery (RFC §8.2):
- transport_http.go: /.well-known/mcp-servers.json advertises both
core-agent and core-mcp with semantic use_when hints
Tool count: 25 → 33. Good/Bad/Ugly coverage added for every new tool.
Pre-existing cmd/mcpcmd Cobra-style build error flagged but untouched
— same cmd vs core.Command migration pattern seen in cmd/api and
cmd/build (which were migrated earlier this session).
Co-Authored-By: Virgil <virgil@lethean.io>
The mcpcmd package was using the removed Cobra-style cli.Command API
(Use/Short/Long/RunE/StringFlag/AddCommand). Rewrites it to the current
core.Command{Description, Action, Flags} path-routed pattern so the
core-mcp binary compiles again. Registers both "mcp" and "mcp/serve"
for parity with the existing OnStartup service-mode flow.
Fixes the bridge DescribableGroup test that expected len == svc.Tools()
but ToolBridge.Describe prepends the GET tool-listing entry, so the
correct expectation is len + 1.
Co-Authored-By: Virgil <virgil@lethean.io>
New tools (RFC §3):
- webview_render / webview_update: embedded UI HTML + state broadcast
via webview.render / webview.update channels with merge-or-replace
- ws_connect / ws_send / ws_close: outbound WebSocket client tools
with stable ws-<hex> connection IDs
- process_run: blocking command executor returning ID/exit/output
- rag_search / rag_index: aliases for rag_query / rag_ingest per spec
- rag_retrieve: fetch chunks for a source, ordered by chunk index
- ide_dashboard_state / ide_dashboard_update: merge-or-replace state
with activity feed entries and dashboard.state.updated broadcast
- agentic_issue_dispatch: spec-aligned name for agentic_dispatch_issue
Discovery (RFC §8.2):
- transport_http.go: /.well-known/mcp-servers.json advertises both
core-agent and core-mcp with semantic use_when hints
Tool count: 25 → 33. Good/Bad/Ugly coverage added for every new tool.
Pre-existing cmd/mcpcmd Cobra-style build error flagged but untouched
— same cmd vs core.Command migration pattern seen in cmd/api and
cmd/build (which were migrated earlier this session).
Co-Authored-By: Virgil <virgil@lethean.io>
The go-sdk fires notifications/tools/list_changed and
notifications/resources/list_changed with 10ms delay after AddTool/AddResource.
Since all registration happens before server.Run(), these hit stdout
before the client sends initialize, breaking the MCP handshake.
Co-Authored-By: Virgil <virgil@lethean.io>
Metrics, RAG, and webview tools only register when CORE_MCP_FULL=1.
Process and WS tools always register (used by factory).
Reduces default tool count by 15.
Co-Authored-By: Virgil <virgil@lethean.io>
- Fix TestBridgeToAPI_Good_EndToEnd: POST with empty JSON body instead of nil
- Add local replace for go-process to resolve API drift with core v0.8.0
Co-Authored-By: Virgil <virgil@lethean.io>