Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
91f4f33
fix: migrate module paths from forge.lthn.ai to dappco.re
Snider Apr 4, 2026
a4b72c6
fix: migrate module paths from forge.lthn.ai to dappco.re
Snider Apr 7, 2026
5f0878d
fix(mcp): update Subsystem interface to match mcp v0.5.1 Service API
Snider Apr 7, 2026
9c6f109
fix(agent): mcp.Register startup panic + test isolation + CLI test st…
Snider Apr 8, 2026
e8862e2
feat(dispatch): LEM profiles + native Claude agents
Snider Apr 8, 2026
7a531d1
perf(mcp): reduce tool count from 189 to 82
Snider Apr 8, 2026
39914fb
refactor: AX compliance sweep — replace banned stdlib imports with co…
Snider Apr 13, 2026
db6d06a
merge: integrate forge dispatch + mcp changes with AX compliance sweep
Snider Apr 13, 2026
edfcb1b
feat(agent): unblock factory dispatch, runtime-aware containers, RFC …
Snider Apr 14, 2026
83364a6
feat(agent): sync backoff + ledger + auto-flush loop
Snider Apr 14, 2026
4684ae7
feat(agent): go-store backing for dispatch state per RFC §15
Snider Apr 14, 2026
716546d
feat(agent): workspace state mirror + ghost reap + sync queue via go-…
Snider Apr 14, 2026
eed2274
feat(agent): pairing-code login per RFC §9 Fleet Mode
Snider Apr 14, 2026
eaf1782
feat(agent): RFC §7 QA capture pipeline
Snider Apr 14, 2026
3646556
feat(agent): RFC §7 Post-Run Analysis — diff + cluster dispatch findings
Snider Apr 14, 2026
03e5934
feat(agent): RFC §15.5 parent workspace stats store
Snider Apr 14, 2026
2fc0de3
feat(agent): RFC §15.5 orphan QA buffer recovery on startup
Snider Apr 14, 2026
5ef2aba
fix(agent): workspace prep falls back to GOWORK search
Snider Apr 14, 2026
30cc423
refactor(agent): runtimeAvailable uses core/process primitive
Snider Apr 14, 2026
b338e12
fix(agent): process action overrides survive ServiceStartup
Snider Apr 14, 2026
9c170db
release: v0.8.0-alpha.1 — OpenBrain integration, fleet pipeline, AX-1…
Snider Apr 25, 2026
c5b08b3
fix(security): remove .gitleaksignore entries with SHAs unreachable f…
Snider Apr 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 2 additions & 2 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dappcore-agent",
"description": "Agentic systems to work on the Lethean Network's dAppCore project",
"name": "core-agent",
"description": "Agentic systems to work on the Lethean Network's core project",
"owner": {
"name": "Lethean Community",
"email": "hello@lethean.io"
Expand Down
15 changes: 5 additions & 10 deletions .codex/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Shared between CLI and IDE extension

model = "gpt-5.4"
model_reasoning_effort = "extra-high"
model_reasoning_effort = "xhigh"
approval_policy = "on-request"
sandbox_mode = "workspace-write"
personality = "pragmatic"
Expand All @@ -12,7 +12,7 @@ personality = "pragmatic"

[profiles.review]
model = "gpt-5.4"
model_reasoning_effort = "extra-high"
model_reasoning_effort = "xhigh"
approval_policy = "never"
sandbox_mode = "read-only"

Expand Down Expand Up @@ -47,14 +47,9 @@ FORGE_TOKEN = "${FORGE_TOKEN}"
CORE_BRAIN_KEY = "${CORE_BRAIN_KEY}"
MONITOR_INTERVAL = "15s"

# Local model providers
[model_providers.ollama]
name = "Ollama"
base_url = "http://127.0.0.1:11434/v1"

[model_providers.lmstudio]
name = "LM Studio"
base_url = "http://127.0.0.1:1234/v1"
# Model providers: codex CLI 0.122+ ships built-in `ollama` and `lmstudio`
# providers pointing at the same default localhost ports, so project-level
# overrides are both redundant and rejected ("reserved built-in provider IDs").

# Agent configuration
[agents]
Expand Down
13 changes: 12 additions & 1 deletion .core/reference/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,18 @@ func (cl *Cli) Run(args ...string) Result {
opts.Set(key, true)
}
} else if !IsFlag(arg) {
opts.Set("_arg", arg)
if !opts.Has("_arg") {
opts.Set("_arg", arg)
}
argsResult := opts.Get("_args")
args := []string{}
if argsResult.OK {
if existing, ok := argsResult.Value.([]string); ok {
args = append(args, existing...)
}
}
args = append(args, arg)
opts.Set("_args", args)
}
}

Expand Down
5 changes: 5 additions & 0 deletions .core/reference/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,11 @@ func (h *ErrorPanic) appendReport(report CrashReport) {
var reports []CrashReport
if data, err := os.ReadFile(h.filePath); err == nil {
if err := json.Unmarshal(data, &reports); err != nil {
Default().Error(Concat("crash report file corrupted path=", h.filePath, " err=", err.Error(), " raw=", string(data)))
backupPath := Concat(h.filePath, ".corrupt")
if backupErr := os.WriteFile(backupPath, data, 0600); backupErr != nil {
Default().Error(Concat("crash report backup failed path=", h.filePath, " err=", backupErr.Error()))
}
reports = nil
}
}
Expand Down
33 changes: 29 additions & 4 deletions .core/reference/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,20 @@ func (m *Fs) WriteMode(p, content string, mode os.FileMode) Result {
// dir := fs.TempDir("agent-workspace")
// defer fs.DeleteAll(dir)
func (m *Fs) TempDir(prefix string) string {
dir, err := os.MkdirTemp("", prefix)
root := m.root
if root == "" || root == "/" {
root = os.TempDir()
} else if err := os.MkdirAll(root, 0755); err != nil {
return ""
}
dir, err := os.MkdirTemp(root, prefix)
if err != nil {
return ""
}
if vp := m.validatePath(dir); !vp.OK {
os.RemoveAll(dir)
return ""
}
return dir
}

Expand Down Expand Up @@ -358,15 +368,30 @@ func WriteAll(writer any, content string) Result {
return Result{E("core.WriteAll", "not a writer", nil), false}
}
_, err := wc.Write([]byte(content))
var closeErr error
if closer, ok := writer.(io.Closer); ok {
closer.Close()
closeErr = closer.Close()
}
if err != nil {
return Result{err, false}
}
if closeErr != nil {
return Result{closeErr, false}
}
return Result{OK: true}
}

func (m *Fs) isProtectedPath(full string) bool {
if full == "/" {
return true
}
home, err := os.UserHomeDir()
if err != nil || home == "" {
return false
}
return full == home
}

// CloseStream closes any value that implements io.Closer.
//
// core.CloseStream(r.Value)
Expand All @@ -383,7 +408,7 @@ func (m *Fs) Delete(p string) Result {
return vp
}
full := vp.Value.(string)
if full == "/" || full == os.Getenv("HOME") {
if m.isProtectedPath(full) {
return Result{E("fs.Delete", Concat("refusing to delete protected path: ", full), nil), false}
}
if err := os.Remove(full); err != nil {
Expand All @@ -399,7 +424,7 @@ func (m *Fs) DeleteAll(p string) Result {
return vp
}
full := vp.Value.(string)
if full == "/" || full == os.Getenv("HOME") {
if m.isProtectedPath(full) {
return Result{E("fs.DeleteAll", Concat("refusing to delete protected path: ", full), nil), false}
}
if err := os.RemoveAll(full); err != nil {
Expand Down
4 changes: 4 additions & 0 deletions .core/reference/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,12 @@ func (r *Runtime) ServiceName() string { return "Core" }

// ServiceStartup starts all services via the embedded Core.
func (r *Runtime) ServiceStartup(ctx context.Context, options any) Result {
if r == nil || r.Core == nil {
return Result{OK: true}
}
return r.Core.ServiceStartup(ctx, options)
}

// ServiceShutdown stops all services via the embedded Core.
func (r *Runtime) ServiceShutdown(ctx context.Context) Result {
if r.Core != nil {
Expand Down
26 changes: 26 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,29 @@
node_modules/
bin/
dist/
.DS_Store
Thumbs.db
.Spotlight-V100
.Trashes
*.swp
*.swo
*~
*.tmp
.env
.env.local
.env.*.local
__pycache__/
*.pyc
.venv/
venv/
build/
*.exe
*.dll
*.so
*.dylib
*.a
*.o
*.class
*.test
coverage.out
*.coverprofile
36 changes: 36 additions & 0 deletions .gitleaksignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# gitleaks ignore — documented false positives
#
# Each line below is a gitleaks fingerprint for a finding that has been
# manually reviewed and confirmed to be a documentation placeholder, test
# constant, env-clearing call, or example-snippet — NOT a real secret.
#
# Filed: Mantis #325. Reviewer: argus + athena. 2026-04-25.
#
# Format per gitleaks: <commit_sha>:<file>:<rule>:<line>
# The file is anchored to per-commit fingerprints so a future legitimate
# leak in the same file/rule will still be caught.
#
# Why ignore:
# - php/docs/api-keys.md — curl example with placeholder Bearer
# - php/View/Blade/admin/api-key-manager.blade.php — curl example
# - php/tests/Unit/ClaudeServiceTest.php — 'test-api-key' literal in tests
# - php/tests/Feature/AgentApiKeyTest.php — 'ak_test_key_*' test fixture
# - php/Services/AgentDetection.php — docblock example string
# - pkg/agentic/prep_test.go — t.Setenv("CORE_BRAIN_KEY", "") env-clear
# - pkg/orchestrator/security_test.go — MaskToken test fixture
# - src/php/* — older copies of the same files (pre-Burst migration)

# pkg/agentic/prep_test.go (CORE_BRAIN_KEY env-clear)
4fe1bf0aff66653a28625adde7df28f9b0b292ab:pkg/agentic/prep_test.go:generic-api-key:151
726a384873dd17e1fb413fb8db9c8e63dd09b826:pkg/agentic/prep_test.go:generic-api-key:151
da6d6cfa1a6e800364e576087524191e141b41d0:pkg/agentic/prep_test.go:generic-api-key:151

# pkg/orchestrator/security_test.go (MaskToken test fixture)
e90a84eaa01dccb9cbf5548bf057745eafa54243:pkg/orchestrator/security_test.go:generic-api-key:107

# php/* + src/php/* fingerprints removed in release/v0.8.0-alpha.1:
# the original pre-squash commit SHAs do not exist in the public github
# mirror's history (CodeRabbit Mantis #929). Re-add fresh suppressions
# with current-SHA fingerprints after the next gitleaks run on the
# public clone confirms the same false-positives still surface in the
# squash-shaped history.
4 changes: 2 additions & 2 deletions .mcp.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"mcpServers": {
"core": {
"type": "stdio",
"command": "core-agent",
"args": ["mcp"]
"command": "core",
"args": ["mcp", "serve"]
}
}
}
39 changes: 39 additions & 0 deletions claude/camofox_mcp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<!-- SPDX-License-Identifier: EUPL-1.2 -->

# camofox-mcp

`camofox-mcp` is a stdio MCP server that wraps the Camofox browser HTTP API for Claude Code.

## Install

Local editable install:

```bash
cd claude/camofox_mcp
pip install -e .
```

Direct git install:

```bash
pip install "git+https://forge.lthn.ai/core/agent.git#subdirectory=claude/camofox_mcp"
```

## Claude Code

```bash
claude mcp add camofox -- camofox-mcp --camofox-url=http://localhost:8099 --api-key=$CAMOFOX_API_KEY
```

If `--api-key` is omitted, the server will read `CAMOFOX_API_KEY` from the environment.

## Tools

- `navigate(url)` opens a new tab and returns `{tab_id, status}`
- `read_page(tab_id)` returns `{text, url, title}`
- `screenshot(tab_id)` returns `{image_b64}`
- `click(tab_id, selector)` returns `{ok}`
- `fill(tab_id, selector, value)` returns `{ok}`
- `close_tab(tab_id)` returns `{ok}`

The server prefers the official Python `mcp` SDK when it is importable. If that package is unavailable at runtime, it falls back to a small stdio JSON-RPC MCP implementation that supports `initialize`, `tools/list`, and `tools/call`.
7 changes: 7 additions & 0 deletions claude/camofox_mcp/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# SPDX-License-Identifier: EUPL-1.2

"""Camofox MCP server package."""

__all__ = ["__version__"]

__version__ = "0.1.0"
26 changes: 26 additions & 0 deletions claude/camofox_mcp/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# SPDX-License-Identifier: EUPL-1.2

[build-system]
requires = ["setuptools>=69", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "camofox-mcp"
version = "0.1.0"
description = "MCP stdio server exposing the Camofox browser HTTP API"
readme = "README.md"
requires-python = ">=3.11"
dependencies = [
"mcp>=1.0.0",
"httpx>=0.28.0",
"pydantic>=2.0.0",
]

[project.scripts]
camofox-mcp = "camofox_mcp.server:main"

[tool.setuptools]
packages = ["camofox_mcp"]

[tool.setuptools.package-dir]
camofox_mcp = "."
Loading