Raw JSON report machine-readable
{
"data": {
"repo": {
"topics": [],
"is_fork": false,
"size_kb": 4705,
"has_wiki": true,
"homepage": "https://majorcontext.com/moat",
"languages": {
"Go": 3473290,
"Shell": 33498,
"Python": 1785,
"Makefile": 2641
},
"pushed_at": "2026-07-23T06:20:33Z",
"created_at": "2026-01-11T00:05:02Z",
"owner_type": "Organization",
"updated_at": "2026-07-17T05:07:24Z",
"description": "Run agents in containers with credential injection and full observability.",
"is_archived": false,
"is_disabled": false,
"license_spdx": "MIT",
"default_branch": "main",
"license_spdx_raw": "MIT",
"primary_language": "Go",
"significant_languages": [
"Go"
]
},
"owner": {
"blog": null,
"name": "Major Context",
"type": "Organization",
"login": "majorcontext",
"company": null,
"location": "United States of America",
"followers": 7,
"avatar_url": "https://avatars.githubusercontent.com/u/256021519?v=4",
"created_at": "2026-01-20T04:21:21Z",
"is_verified": null,
"public_repos": 6,
"account_age_days": 186
},
"license": {
"state": "standard",
"spdx_id": "MIT",
"raw_spdx": "MIT",
"file_present": true,
"scorecard_found": true,
"profile_has_license": true
},
"activity": {
"releases": [
{
"tag": "v0.6.1",
"kind": "patch",
"published_at": "2026-06-19T03:35:58Z"
},
{
"tag": "v0.6.0",
"kind": "minor",
"published_at": "2026-06-17T16:04:58Z"
},
{
"tag": "v0.5.4",
"kind": "patch",
"published_at": "2026-06-01T18:29:12Z"
},
{
"tag": "v0.5.3",
"kind": "patch",
"published_at": "2026-05-25T22:58:07Z"
},
{
"tag": "v0.5.2",
"kind": "patch",
"published_at": "2026-05-21T21:13:28Z"
},
{
"tag": "v0.5.1",
"kind": "patch",
"published_at": "2026-04-28T22:17:31Z"
},
{
"tag": "v0.5.0",
"kind": "minor",
"published_at": "2026-04-07T17:57:16Z"
},
{
"tag": "v0.4.0",
"kind": "minor",
"published_at": "2026-03-19T00:55:00Z"
},
{
"tag": "v0.3.3",
"kind": "patch",
"published_at": "2026-03-07T01:08:35Z"
},
{
"tag": "v0.3.2",
"kind": "patch",
"published_at": "2026-03-06T00:37:31Z"
},
{
"tag": "v0.3.1",
"kind": "patch",
"published_at": "2026-03-04T23:28:32Z"
},
{
"tag": "v0.3.0",
"kind": "minor",
"published_at": "2026-03-04T19:06:17Z"
},
{
"tag": "v0.2.0",
"kind": "minor",
"published_at": "2026-02-11T05:00:19Z"
},
{
"tag": "v0.1.0",
"kind": "minor",
"published_at": "2026-02-08T19:06:08Z"
}
],
"recent_commits": [
{
"oid": "616123618c8032ff42c3b6406aa6f4aba1ca0130",
"body": "* feat(copilot): carry over host settings into container\n\nRead ~/.copilot/settings.json and optional ~/.moat/copilot/settings.json\noverrides, filter through an allowlist of safe/useful settings, and write\nthe merged result to the container staging directory.\n\nCarried over: statusLine, theme, model, \n[…]\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>\n\n---------\n\nCo-authored-by: Andrii Bezzub <andrew@bezzub.com>\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
"is_bot": false,
"headline": "feat(copilot): carry over host settings into container (#438)",
"author_name": "Andrew Bezzub",
"author_login": "abezzub-dr",
"committed_at": "2026-07-17T05:07:19Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "742a3a2ce943c205f87637149b059fb949a12e20",
"body": "Add copilot.context and copilot.reasoning_effort to moat.yaml, with\ncorresponding --context and --reasoning-effort CLI flags. CLI flags\noverride config values, matching the existing --model precedence.\n\nThis lets users pin context window tier (default/long_context) and\nreasoning effort level (none/minimal/low/medium/high/xhigh/max)\ndeclaratively so settings persist across moat runs.\n\nCo-authored-by: Andrii Bezzub <andrew@bezzub.com>",
"is_bot": false,
"headline": "feat(copilot): add context and reasoning_effort config fields (#437)",
"author_name": "Andrew Bezzub",
"author_login": "abezzub-dr",
"committed_at": "2026-07-14T06:00:20Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "2012cecb2189574b66c74bb2cb17450f8354ba9c",
"body": "* fix(daemon): raise proxy daemon file-descriptor limit at startup\n\nThe proxy daemon is the single shared egress point for every run. It\ninherited the host's default RLIMIT_NOFILE soft limit (typically 256 on\nmacOS), so a burst of concurrent connections through the one proxy —\ne.g. `bun install` ope\n[…]\ncepts, and treat a limit that cannot be raised\nfurther as success rather than a spurious error — avoiding a misleading\n\"could not raise\" warning at startup when the existing limit is already\nadequate.",
"is_bot": false,
"headline": "fix(daemon): raise proxy daemon file-descriptor limit at startup (#439)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-07-14T05:59:54Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "cdd9c7edde565ea1afbc5b976e4fff214c8897c6",
"body": "* feat(copilot): add GitHub Copilot CLI support\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>\n\n* test(copilot): cover grant and refresh paths\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>\n\n* fix(copilot): address provider review findings\n\nCo-authored-b\n[…]\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>\n\n---------\n\nCo-authored-by: Andrii Bezzub <andrew@bezzub.com>\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
"is_bot": false,
"headline": "feat(copilot): add GitHub Copilot CLI support (#436)",
"author_name": "Andrew Bezzub",
"author_login": "abezzub-dr",
"committed_at": "2026-07-08T20:10:08Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "9716c7d2974810869e6546db6601bead6a41f827",
"body": "* docs(plans): add Pi config bridge (global settings + build-time packages) design\n\n* docs(plans): add Pi config bridge implementation plan\n\n* feat(config): add pi.packages with remote-source validation\n\n* feat(pi): generate build-time Dockerfile snippet for packages + safe settings\n\n* feat(pi): wir\n[…]\nges is set but pi-cli isn't a dependency\n\nAddresses review nit: via 'moat run --agent pi' without pi-cli in dependencies,\npi.packages would be silently skipped (PiBakeSettings stays false). Fail loud.",
"is_bot": false,
"headline": "feat(pi): build-time Pi packages + Moat-owned safe settings (#434)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-07-03T05:36:14Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "0601a900cf871dc4437d59af2475b5a0cf1950e6",
"body": "* docs(plans): add Pi coding agent provider design spec\n\n* docs(plans): record Pi HTTP_PROXY spike result (Outcome A) in design\n\n* docs(plans): add Pi coding agent provider implementation plan\n\n* feat(pi): scaffold Pi provider package and register pi-cli dependency\n\n* feat(pi): add resolvePiProvider\n[…]\ntree config\n\nGuards the worktree config-source fix: a worktree branch's own moat.yaml must\nreach Preflight, not the pre-worktree workspace config. Verified the test fails\nagainst the pre-fix ordering.",
"is_bot": false,
"headline": "feat(pi): add Pi coding agent provider (#433)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-07-02T04:49:03Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "fad2897b1881ba85831d6b4397d26066bec04b18",
"body": "…gs (#432)\n\nThe claude-review job's --allowedTools only permitted a few `gh` commands,\nand the job had no Go toolchain, so every review fell back to static-only\nanalysis and closed with \"I could not run go build/go vet/go test in this\nsandbox\" — never actually running the tests it recommended.\n\nAdd \n[…]\nfmt, make, and golangci-lint, and\ntell the reviewer in the prompt to use them. The job is already gated to\nsame-repo PRs, so executing PR test code is the same trust boundary as the\nexisting Test job.",
"is_bot": false,
"headline": "ci(review): let the review bot run go build/vet/test to verify findin…",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-07-01T20:51:22Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "48090d359abed34293f75e49141a77678d5e3699",
"body": "…g (#431)\n\n* fix(runctx): make injected agent context reflect real container config\n\nThe \"Moat Environment\" instructions file injected into agent containers\nmisrepresented the run's actual configuration:\n\n- Network policy: it listed grant/rule hosts under \"Allowed hosts\"\n regardless of policy. Unde\n[…]\nombination\n\nBoth review passes noted TestRender_dockerSection left host+strict\nunverified. The caveat is keyed on policy, not mode, so the path was\nalready correct; add the row to complete the matrix.",
"is_bot": false,
"headline": "fix(runctx): make injected agent context reflect real container confi…",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-07-01T20:51:18Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "d145027480dae277a1965c4150ca297cfe729aa6",
"body": "* feat(deps): add opentofu and terragrunt managed dependencies\n\nAdd two cloud tools as github-binary registry entries, requiring no Go\ninstaller code:\n\n- opentofu: installs the OpenTofu CLI as the `tofu` command from a tar.gz\n release asset.\n- terragrunt: installs the Terragrunt orchestration wrapp\n[…]\nnary (extension-less) assets install straight to /usr/local/bin/<name>\nvia the raw branch of buildArchDetectCommand, which never reads\narchBinarySpec.bin. Drop the field and note why, per code review.",
"is_bot": false,
"headline": "feat(deps): add opentofu and terragrunt managed dependencies (#430)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-07-01T20:04:47Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "00042abed60e68257eefac77eb6d373a39711b45",
"body": "* refactor(run): extract Claude container staging from Create\n\nMove the Claude staging body into setupClaudeStaging in manager_agentinit.go:\nthe proxy-relay MCP server config, the claude>anthropic credential lookup,\nlocal-MCP conversion, PrepareContainer, and the settings.json write\n(ApplyRunPolicy \n[…]\nider fake needed.\nBehavior-identical (verified line-for-line against main).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "refactor(run): extract Claude container staging from Create (#429)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-07-01T01:30:20Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "68b61252106c5de4953e68387808b8d9754544b3",
"body": "refactor(run): extract Gemini staging + dedupe MCP config builder\n\nMove the Gemini staging body into setupGeminiStaging in manager_agentinit.go,\nmirroring setupCodexStaging (Create ~2,192 -> ~2,132 lines).\n\nAlso dedupe the ~35 lines of local-MCP grant/env-placeholder building that\nCodex and Gemini s\n[…]\nd a\ngrant injecting an env placeholder without mutating the original spec env) —\nunit-testable now since the helper has no provider dependency.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "refactor(run): extract Gemini container staging from Create (#428)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-30T22:44:09Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "c811daffa3e5f38f4b940d5f466239164f12ebbd",
"body": "Move the Codex staging body (OpenAI credential lookup, local-MCP config\nbuild with grant validation, PrepareContainer call) out of Create into\nsetupCodexStaging in the new manager_agentinit.go. Create shrinks ~2,251 ->\n~2,192 lines.\n\nBehavior-preserving. The `provider.GetAgent(\"codex\") == nil` check\n[…]\ngo covering the two grant-validation errors\n(unknown grant, grant not declared), which return before PrepareContainer so\nthey need no provider.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "refactor(run): extract Codex container staging from Create (#427)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-30T22:37:06Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "c5614bde51de16bf61df6cdafe98a743625dd3c0",
"body": "Move the provider-specific container mounts + init-files setup out of Create\ninto setupProviderMounts in manager_provider.go: it walks the run's grants,\ncollects each provider's container mounts and init files, and records\nprovider cleanup paths on the Run. Create shrinks ~2,288 -> ~2,251 lines; the\n[…]\nr, and a grant whose credential is missing (skipped). The\npopulated path needs a registered provider + stored credential and stays\ne2e-covered.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "refactor(run): extract provider mounts/init-files from Create (#426)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-29T01:18:51Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "e1936204e79550083db4fbc4650cd72be4bfe4af",
"body": "…e (#425)\n\nMove the memory/CPUs/DNS/ulimits computation out of Create into a pure\nresolveResourceLimits method in manager_resources.go. Priority is unchanged\n(explicit moat.yaml > agent provider default > runtime fallback), including\nthe Apple-container AI-agent 8 GB default. Create shrinks ~2,315 -\n[…]\nagation +\nulimit sorting, the Apple AI-agent default, the non-AI no-default case, and\nexplicit memory taking precedence over the Apple default.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "refactor(run): extract container resource-limit resolution from Creat…",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-29T00:58:34Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "c8dabc13579c6886183b75c44353848ff2c64cb3",
"body": "Move the network-mode/extra-hosts computation out of Create into a pure\nresolveNetworkConfig method in manager_network.go: given whether the run\nneeds published ports or proxy access, it picks host vs bridge mode and the\nextra host mappings. Create shrinks ~2,353 -> ~2,315 lines.\n\nBehavior-preservin\n[…]\nanager_network_test.go covering the none/host/bridge paths (including\na no-host-network runtime stub), which the extraction made unit-testable.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "refactor(run): extract network-mode resolution from Create (#424)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-29T00:43:05Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "6068b8daa91f738a5614c4a485dec77077cde388",
"body": "… (#423)\n\n* refactor(run): extract SSH agent setup from Create into setupSSHAgent\n\nThe SSH-agent-proxy wiring (~145 lines: load SSH key mappings, connect the\nupstream agent, start a TCP or Unix-socket filtering proxy, and produce the\ncontainer env/mounts) was inline in Create. Move it into a setupSS\n[…]\nmount wiring) still need a real/faked agent and remain covered\nonly by e2e.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "refactor(run): extract SSH agent setup from Create into setupSSHAgent…",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-29T00:23:52Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "826296ad4c2e981084826bdc3ab303eb7870bd39",
"body": "Create opened the credential store via credential.NewFileStore at seven\nseparate sites — grant validation, the proxy credential loop, SSH mapping\nlookup, provider mounts, and the Claude/Codex/Gemini init paths — each\nfirst deriving the encryption key with credential.DefaultEncryptionKey(),\nwhich can\n[…]\nndant\nkeychain access) are removed. The separate store opens in grants.go and\nimageneeds.go are on different call paths and are left untouched.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "refactor(run): open the credential store once in Create (#422)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-28T23:55:04Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "dcf11577b9ab88861da732f0c336ae8b17c93d82",
"body": "manager.go had grown to ~4,720 lines, with the Create setup pipeline alone\nspanning ~2,500. Carve the Manager methods out of the single god-file into\nsix purpose-named files, all still package run:\n\n manager.go core: types, constructors, runtime helpers,\n acces\n[…]\nep of the manager.go decomposition; phase extractions (e.g. folding\nthe credential store opened 7x in Create down to once) follow in later PRs.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "refactor(run): split manager.go into purpose-named files (#421)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-28T02:52:02Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "0e8e73f4356bd9a0541c9abe9b06c5520d338d5a",
"body": "Manager.Start took a zero-field StartOptions{} at every call site. Remove\nthe type and simplify the signature to Start(ctx, runID string); when a\nreal option appears, add it back with a concrete field driving it.\n\nUpdated all 57 call sites (mostly e2e tests). Verified under -tags=e2e.\nThe unrelated Docker SDK container.StartOptions{} is untouched.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "refactor(run): drop the empty StartOptions struct (#420)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-27T06:30:09Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "fa37c78f5da5d649e92c26da3727f8b241ffbe1c",
"body": "* build: adopt gofumpt as the canonical formatter\n\n- golangci-lint: switch the configured formatter from gofmt to gofumpt\n (a stricter superset). `golangci-lint run` now enforces it, so the\n manual `gofmt -l` CI step is removed as redundant.\n- Claude Code hook (.claude/hooks/go-fmt.py): format edi\n[…]\nfumpt in the test job so test 6 actually exercises the hook's\ngofumpt path.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "build: adopt gofumpt as the canonical formatter (#419)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-27T04:00:18Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "a05e740a9d647c32edafedd703a897821cb886a7",
"body": "* chore(lint): enable exhaustive and testifylint\n\nRaise the lint floor with two checks that catch real classes of issue:\n\n- exhaustive (with default-signifies-exhaustive: true): enum switches must\n handle every case or have a default. Of the switches flagged, 14 already\n have a default; the 5 with\n[…]\ne case,\nand keeps the linter able to flag a future controlSeqKind addition.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "chore(lint): enable exhaustive and testifylint (#418)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-27T02:19:55Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "70763c185900d490e85d7a83177ac6266bdc2ac4",
"body": "…ties (#417)\n\n* chore(security): pin Go 1.25.11 toolchain to clear stdlib vulnerabilities\n\nThe remaining govulncheck findings after the dependency bumps (#416) were\n~16 Go standard-library vulnerabilities (crypto/x509, crypto/tls,\nhtml/template, net/*, archive/tar, …), all fixed in Go 1.25.7–1.25.11\n[…]\nhropic.com>\n\n* docs(changelog): security entry for Go toolchain bump (#417)\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "chore(security): pin Go 1.25.11 toolchain to clear stdlib vulnerabili…",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-27T00:19:25Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "cf957b9b5304d988d2eb0081319881c7a33fbe72",
"body": "* refactor(errors): sentinel-based not-found taxonomy\n\nMake \"not found\" matchable via errors.Is instead of error-string\ninspection, and give the run package a single canonical sentinel.\n\n- credential: add ErrNotFound; FileStore.Get now wraps it with %w.\n- cmd/moat/cli: grant_show matches credential.\n[…]\ntching the\nexisting ErrNotFound test (decrypt was only covered indirectly).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "refactor(errors): sentinel-based not-found taxonomy (#415)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-26T23:47:32Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "c6efd8e7897616c1da856db1cf197898a5e619e2",
"body": "… (#416)\n\n* chore(security): upgrade dependencies to clear called vulnerabilities\n\ngovulncheck reported 36 vulnerabilities the code actually calls. Upgrading\nthe deps with available fixes clears 15 of them (build + tests green):\n\n- containerd/v2 v2.2.1 -> v2.2.5 (6 CVEs)\n- golang.org/x/cryp\n[…]\nic.com>\n\n* docs(changelog): security entry for dependency vuln fixes (#416)\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "chore(security): upgrade dependencies to clear called vulnerabilities…",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-26T23:47:00Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "916b0116ad5488174e96211750d51c5409809936",
"body": "* docs: polish wave 1 — package docs, examples, and idiom cleanups\n\nFrom the code-quality audit. Verified, low-risk, high-visibility polish:\n\nDocumentation (the signature items)\n- internal/run/doc.go: document the run lifecycle state machine and the\n concurrency invariants (single-goroutine exit mo\n[…]\no package docs (useful to anyone reading the source) and drop the\nExamples.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs: polish wave 1 — package docs, examples, and idiom cleanups (#414)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-26T22:36:23Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "c9e427666e88d3d2e8a77090017132600b52a041",
"body": "* chore: audit quick-win cleanups\n\nVerified, low-risk cleanups from the architecture sweep:\n\n- credential: delete the dead ProviderSetup registry (ProviderSetup,\n ProviderResult, providerSetups, RegisterProviderSetup, GetProviderSetup)\n and its tests — zero non-test callers; the live registry is\n \n[…]\no\nsort path via rust (3 ENV vars), asserting sorted + deterministic output.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "chore: audit quick-win cleanups (#413)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-26T20:53:56Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "6784e8ddc7fb01231de018bcc17d41b792aa44d4",
"body": "* fix: correctness fixes from architecture audit\n\nThree confirmed latent bugs surfaced by the codebase sweep:\n\n- routing: write routes.json atomically (temp + rename) so a crash\n mid-write can't leave a truncated file every proxy then fails to parse.\n- config: LoadGlobal no longer silently swallows\n[…]\ns, not just\n Proxy.Port; assert no temp file lingers after an atomic save.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix: correctness fixes from architecture audit (#412)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-26T20:17:05Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "22ebe3c752fa72ce4e7507169de4d2c8a78d5aff",
"body": "Follow-up to #409, addressing its first review pass:\n\n- The actionable port-in-use error wrapped the raw error with %w, so the\n user-visible string still ended with \"...: listen tcp 127.0.0.1:8080:\n bind: address already in use\" — re-introducing the exact noise the\n message was meant to replace. \n[…]\n: assert both documented remedies (MOAT_PROXY_PORT and\n proxy.port) and the port number appear, and that the raw bind error is\n not embedded.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(routing): drop raw bind-error noise from port-in-use message (#411)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-26T17:54:50Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "8b8deafcfa2ad1c25f01086606930f2e306f17b0",
"body": "* chore(daemon): remove redundant daemon-hosted routing proxy\n\nThe daemon started a second routing proxy (routing.NewProxyServer +\nStart(0)) on a random port, serving the same routes.json as the per-agent\nrouting proxy that `moat run` actually advertises. Its port was only\nlogged — never persisted, \n[…]\ncomment style; keep the note that the daemon does not host a routing proxy.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "chore(daemon): remove redundant daemon-hosted routing proxy (#410)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-26T17:27:00Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "cdf91976f9fb2dabc4db292be76745bd7d1e3ba0",
"body": "* feat(routing): discovery index pages at the proxy root\n\nThe routing proxy now serves a discoverable index instead of an error or\na nondeterministic guess at its bare hosts:\n\n - http://localhost:8080 lists every running agent and its endpoints\n - http://demo.localhost:8080 lists that agent's\n[…]\ne\n\nMatch the actual agentEntry serialization (name + base_url + endpoints).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(routing): discovery index pages at the proxy root (#407)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-26T17:02:47Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "c983aed9b56cc4ef5db8ea6713dc39fd6f5057b2",
"body": "* fix(routing): actionable error when the routing port is in use\n\nThe routing proxy binds a deterministic port (default 8080, configurable\nvia MOAT_PROXY_PORT / proxy.port) and intentionally does not fall back to\na random port — advertised endpoint URLs must stay stable. When that port\nis taken, sur\n[…]\nropic.com>\n\n* docs(changelog): add routing port-in-use error entry for #409\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(routing): actionable error when the routing port is in use (#409)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-26T16:39:49Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "1a3565529d37f8b4f2855c38edf8fee264c90521",
"body": "…st isolation (#406)\n\n* fix(container): support Apple container CLI 1.0.0 schema and keychain test isolation\n\nThe Apple `container` CLI 1.0.0 changed its `inspect`/`list --format json`\noutput: `status` became an object (`status.state`, `status.networks`) instead\nof a string, and image/creation metad\n[…]\nntainerIP retry/timeout/transient-error tests only injected\nlegacy-schema inspect JSON, so the 1.0.0 status.networks path through the\nretry loop was untested. Parameterize all three over both schemas.",
"is_bot": false,
"headline": "fix(container): Apple container CLI 1.0.0 compatibility + keychain te…",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-26T01:40:45Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "9505e6dd82f20cd839712656932c6d6f68ee20d9",
"body": "* feat: volume-mode workspaces\n\nAdd `workspace.mode: volume` (and `--workspace-mode volume`): copy the host\nworking tree into an ephemeral per-run Docker named volume (`moat-ws-<run-id>`)\ninstead of bind-mounting /workspace — for host protection and faster macOS I/O.\nChanges are extracted via snapsh\n[…]\nstill taken).\n\nMinor (review): write snapshots.json with 0600 to match the archive files it\nsits beside; the metadata itself is non-sensitive but the consistency is nicer\nin a restricted snapshot dir.",
"is_bot": false,
"headline": "feat: volume-mode workspaces (#404)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-25T20:44:07Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "9d828be3d7c34652d7f9bf888ba8d237490103bc",
"body": "* feat(config): add type field (bind|volume) to volumes\n\n* feat(container): support named-volume mounts in MountConfig\n\n* feat(run): mount type:volume as native Docker volume + chown via moat-init\n\n* feat(init): chown named-volume mount roots to moatuser\n\n* docs: document volumes type: volume (nativ\n[…]\nists (idempotency on the hot path). [finding 4]\n- move volumeMount's doc comment back to volumeMount (it had been stranded above\n configHasNamedVolumes, leaving volumeMount undocumented). [finding 5]",
"is_bot": false,
"headline": "feat: native (in-VM) volume support via volumes type: volume (#402)",
"author_name": "Andrew Bezzub",
"author_login": "abezzub-dr",
"committed_at": "2026-06-24T00:56:30Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "3f1acc1aea5689ca63096c52f72de37d2716ef3c",
"body": "…rer switch (#400)\n\n* fix(claude): keep bypass-permissions mode across the fullscreen-renderer switch\n\nClaude Code re-execs its own process when switching to the new fullscreen\nrenderer (the \"Try the new fullscreen renderer?\" upsell or silent\nauto-graduation), dropping the original CLI flags — inclu\n[…]\nelow.\n- Document that a default `moat claude` run sets permissions.defaultMode to\n bypassPermissions (overriding a persisted defaultMode), and that --noyolo\n preserves your own permissions settings.",
"is_bot": false,
"headline": "fix(claude): keep bypass-permissions mode across the fullscreen-rende…",
"author_name": "Andrew Bezzub",
"author_login": "abezzub-dr",
"committed_at": "2026-06-24T00:18:10Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "8cad0ed952596b415e2274a5fcd45920edc10c88",
"body": "* fix(tui): forward mouse-mode set/reset to host in compositor mode\n\nWhen a child opens a fullscreen view, moat enters compositor mode and\nfeeds the child's output into an internal VT emulator. Mouse-tracking DEC\nprivate modes (?1000/1002/1003/1005/1006/1007/1015/1016) were swallowed\nby the emulator\n[…]\n disabled on compositor exit,\nReset, and Cleanup if the child (or a crash) leaves them on. Non-mouse\nprivate modes stay with the emulator.\n\n* docs(changelog): add mouse-mode compositor leak fix (#394)",
"is_bot": false,
"headline": "fix(tui): forward mouse-mode set/reset to host in compositor mode (#394)",
"author_name": "Andrew Bezzub",
"author_login": "abezzub-dr",
"committed_at": "2026-06-23T00:59:43Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "5de8cfb0c9d40e26049df482202c13bd3f6e703d",
"body": "* feat(keep): inspect HTTP request bodies in network policies\n\nExpose the parsed JSON request body to http-scope Keep policies as\nparams.body, so network.keep_policy file/pack rules can match on body\ncontent (e.g. block a request whose body carries a secret) instead of\nhost/method/path alone.\n\n- Bum\n[…]\nf a repo-relative path, per CLAUDE.md doc-URL convention.\n- policyRequiresBody: wrap the per-policy compile in a closure with\n defer eng.Close() so the engine is released even if RequiresBody panics.",
"is_bot": false,
"headline": "feat(keep): inspect HTTP request bodies in network policies (#395)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-23T00:49:04Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "9b0628c235c6b6efc78cdbb019aec233eddcdda4",
"body": null,
"is_bot": false,
"headline": "chore(release): v0.6.1 (#393)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-19T03:32:08Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a73c090c37c51c7a86d57b47d30ae023d04526fb",
"body": "…e (#392)\n\n* fix(daemon): scope OAuth token refresh to the run's credential profile\n\nThe shared proxy daemon refreshed OAuth tokens via\ncredential.DefaultStoreDir(), which resolves against the daemon\nprocess's global credential.ActiveProfile. The daemon serves runs from\nevery profile and its ActiveP\n[…]\n instead of the self-contradicting 'no user action required'.\n\nDeferred (documented residual risk, out of scope for this fix): daemon\ncapability negotiation + warn for new-CLI/old-daemon version skew.",
"is_bot": false,
"headline": "fix(daemon): scope OAuth token refresh to the run's credential profil…",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-19T03:20:16Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "d87a8630efab0f8522884450a14aa274ee0cfb18",
"body": "* docs(mcp): frame host-local MCP credential isolation; add example\n\nHost-local MCP servers were already supported and documented, but framed\npurely as connectivity (containers can't reach host localhost). Add the\ncredential-isolation framing: running the server on the host keeps\nhost-only credentia\n[…]\n examples/mcp-hostlocal/server.js\n\nCo-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>\n\n---------\n\nCo-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>",
"is_bot": false,
"headline": "docs(mcp): frame host-local MCP credential isolation; add example (#391)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-18T17:15:25Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "68a82d8e772526bd1407f332dbf0b95899e2ac4b",
"body": "Codify the classes the claude-review bot has repeatedly caught (PRs\n#357, #376, #383-#386, #389) so they're pre-empted before PR time:\n\n- CI: fail the lint job if an unfilled #NNN PR-link placeholder remains\n in CHANGELOG.md (slipped through on #383 and #384).\n- CLAUDE.md 'Codebase Invariants': ran\n[…]\nrity, catalog\n auth-type filtering, and documented-contract matching.\n- CLAUDE.md 'Before You Push': self-review the diff with /code-review,\n re-read open PR threads, check the high-frequency traps.",
"is_bot": false,
"headline": "chore(ci): add review-prevention guardrails (#390)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-18T03:09:31Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "dcf9f3181b4e633ef2e948b9e342c13a2ee094db",
"body": "* docs(plans): design for inline grant prompting on missing grants\n\n* feat(run): export grant helpers for CLI pre-flight\n\n* feat(run): add DetectMissingGrants structured detection\n\n* feat(cli): add --no-prompt flag for grant prompting\n\n* feat(cli): grantInline dispatch to existing grant flows\n\n* fea\n[…]\nand read failure. Read\nfailures are non-promptable and carry the raw store error in a new\nMissingGrant.Detail field, which promptLoop surfaces instead of the\ngeneric 'cannot grant interactively' line.",
"is_bot": false,
"headline": "feat(cli): inline grant prompting for missing credentials (#389)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-18T02:02:45Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "ebcc7f60f31fae019ace89d4cdad769f913cf7ec",
"body": null,
"is_bot": false,
"headline": "chore(release): v0.6.0 (#388)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-17T16:00:40Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ce12113015f45ada84aa447608447720e8066859",
"body": "… (#387)\n\n* fix(mcp): address proxy relay via moat-proxy so the token is stripped\n\nThe MCP relay URL written into .claude.json used the raw host-gateway IP\n(GetHostAddress), which is not in NO_PROXY. The container's MCP client\ntherefore reached the proxy *through* the CONNECT tunnel, so the proxy sa\n[…]\neader comment to grant all three servers, so the example\n is self-documenting. (MCP grants are auto-applied from the mcp: list\n via appendMCPGrants, but listing them makes the requirement explicit.)",
"is_bot": false,
"headline": "fix(mcp): address proxy relay via moat-proxy so the token is stripped…",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-17T15:56:01Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "7cc343db0acad4ffb2925cbb52ca22f18409e2f6",
"body": "* feat(mcp): add Langfuse regional MCP shortcuts\n\nAdd four catalog entries — langfuse-eu, langfuse-us, langfuse-jp, and\nlangfuse-hipaa — pointing at each region's /api/public/mcp endpoint.\nAll share a single mcp-langfuse grant with Basic auth on the Authorization\nheader. No bare `langfuse` alias: fo\n[…]\nfix(mcp): address review feedback on Langfuse entries\n\n- CHANGELOG: replace #NNN placeholder with #384\n- registry.yaml: convert langfuse auth blocks from inline flow to block\n style to match context7",
"is_bot": false,
"headline": "feat(mcp): add Langfuse regional MCP shortcuts (#384)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-17T04:52:18Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "5ba011c60b8d376863a06f09690fd47ba6ef9417",
"body": "…(#386)\n\n* feat(mcp): adopt mcp:<name> grant naming, accept mcp-<name> (deprecated)\n\nAlign MCP API-key grants with the oauth:<name> convention by introducing\nmcp:<name> (colon) as the canonical form. moat grant mcp <name> now stores\nthe credential as mcp:<name> and prints grant: mcp:<name> in its sn\n[…]\nantName\n\nGrantName(\"mcp:\") and GrantName(\"mcp-\") previously returned (\"\", true),\naccepting an empty server name. Add a non-empty guard so the empty-suffix\ncase returns (\"\", false), with test coverage.",
"is_bot": false,
"headline": "feat(mcp): adopt mcp:<name> grant naming (mcp-<name> still accepted) …",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-17T04:44:23Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "61d205cefe19c1c4636682d1071056a7557bbcd2",
"body": "…ion (#385)\n\n* feat(proxy): add 'moat proxy restart' with version-aware daemon adoption\n\nAdd a 'moat proxy restart' subcommand that atomically replaces the proxy\ndaemon without a health monitor sneaking an old daemon into the gap.\n\n- New daemon.Restart holds the spawn lock across the whole stop->sta\n[…]\nck+socket (avoids a\n redundant, misleading second cleanup)\n- EnsureRunning version-adoption: clearer 'version adoption' log line and\n a comment documenting the two-known-version flip-flop limitation",
"is_bot": false,
"headline": "feat(proxy): add 'moat proxy restart' with version-aware daemon adopt…",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-17T04:44:03Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "c14cd240bf3abadc25a2e35e182da3e321d14b6b",
"body": "* docs(plans): add declarative MCP shorthand design spec\n\n* docs(plans): add declarative MCP shorthand implementation plan\n\n* feat(mcpcatalog): add well-known MCP server catalog leaf package\n\n* refactor(oauth): delegate server-URL lookup to mcpcatalog\n\n* feat(config): accept bare MCP server name in \n[…]\n7,\ngrant mcp-context7), so 'moat grant oauth context7' no longer attempts a doomed\ndiscovery. Also assert catalog auth is filled when an explicit url is set.\n\nAddresses claude-review feedback on #383.",
"is_bot": false,
"headline": "feat: declarative MCP shorthand for well-known servers (#383)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-17T03:41:06Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "e80c600db8374bd96019f694b0c78068b93afc8e",
"body": "* feat(oauth): add posthog to the OAuth MCP auto-discovery registry\n\nRegisters https://mcp.posthog.com/mcp so `moat grant oauth posthog`\nauto-discovers OAuth endpoints without --url or a config file, matching\nthe other well-known services. PostHog's MCP server honors MCP OAuth\ndiscovery (RFC 9728 + \n[…]\n\ncopying it verbatim into moat.yaml failed config validation with\n\"'auth.header' is required when auth is specified\". Emit\n`header: Authorization` (the proxy adds the Bearer prefix for oauth:\ngrants).",
"is_bot": false,
"headline": "feat(oauth): add posthog OAuth/MCP auto-discovery shortcut (#382)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-17T02:45:56Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "5b48a97af746e84f982c843d97aa21cf30d7b37e",
"body": "…ected (#380)\n\n* fix(github): surface re-grant hint when an injected credential is rejected\n\nWhen a stored GitHub token is expired/invalid, HTTPS git failed with only git's\nopaque 'could not read Username' — the proxy's 401 was buried in the network\nlog. After a non-interactive run, moat now scans t\n[…]\nlater rejection now\nun-recovers a prior success (delete(succeeded, host)), processing requests in\nthe network log's chronological order. Adds tests for [200,401] (flags) and\n[200,401,200] (recovered).",
"is_bot": false,
"headline": "fix(github): surface re-grant hint when an injected credential is rej…",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-17T01:41:28Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "4add0207ae18f464c70b3f83e66edf6321bed25e",
"body": "…nt takes effect (#373) (#381)\n\n* fix(github): stop proactively refreshing env-sourced tokens (#373)\n\nThe daemon's background token-refresh re-derived the GitHub token from its own\nprocess env, which is frozen at daemon spawn. After 'moat grant github' with a\nfresh token, the daemon kept injecting (\n[…]\neview: the SourceEnv comment said 'refreshable', which is no\nlonger accurate now that env-sourced tokens are static. Clarify both source\ncomments, and link the changelog entry to the PR per CLAUDE.md.",
"is_bot": false,
"headline": "fix(github): stop proactively refreshing env-sourced tokens so re-gra…",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-17T01:33:53Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "9316faf87c764f116011fecee58606fbcadaae2e",
"body": "* docs(plans): design for multi-agent join (moat join)\n\nSpec for running a second agent inside an already-running container via a new\nrun-first verb, moat join <run> <agent>. Covers syntax (sibling of exec),\nowner-owned lifecycle, same-provider v1 scope inheriting the run's proxy token,\nhybrid obser\n[…]\node-on-cancel trade-off.\n- joined_test: use filepath.Join for the seeded entry.\n\n* test(run): use filepath.Join consistently in prune-test stat check\n\n* docs: add moat join to the README command table",
"is_bot": false,
"headline": "feat: moat join — run a second agent in a running container (#379)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-17T00:01:15Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "0f6183c9fd99dfc0f35245600a4dd2c858bc55ce",
"body": "… (#378)\n\n* test(daemon): regression test for MCP relay token-path routing\n\nGuards the contract behind issue #348: moat builds MCP relay URLs as\n/mcp/{token}/{server} and the credential proxy must route them to the\nper-run server resolved from {token}, rather than treating the token as\nthe server na\n[…]\ntoken-path\nrequest 404s with the token misread as the server name — the explicit red half\nof the regression guard.\n\n* test(daemon): note the #348 failure-mode assertion tracks gatekeeper's 404 wording",
"is_bot": false,
"headline": "test(daemon): regression test for MCP relay token-path routing (#348)…",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-16T04:00:51Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "3348e5e4c76bc3edbe56e3e409203d7b6c900ead",
"body": "* fix(container): report pre_run hook failures clearly\n\nA failing `hooks.pre_run` command aborted the container entrypoint under\n`set -e` with a bare exit code and no indication the pre_run hook was the\ncause, so the failure looked like the container itself failed to start and\nthe real error was eas\n[…]\n wraps the hook in a subshell so its cd can't change the\nentrypoint's cwd; the gosu branch runs in a separate process and needs no\nsubshell. Note both so a future edit doesn't trip over the asymmetry.",
"is_bot": false,
"headline": "fix(container): report pre_run hook failures clearly (#377)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-16T03:09:11Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "02b212f5ac0d9030b46fe7159662f34197888fa9",
"body": "…rvice IP) (#367)\n\n* fix(container): retry Apple network deletion through async container detach\n\nApple's container CLI removes containers asynchronously, so the\n`container network delete` issued during run teardown often fired before\nthe run's containers had detached, failing with \"active container\n[…]\nt on an empty ID for ~3s before failing with a\nconfusing \"no network address found for container \". Surface the raw run\noutput immediately instead.\n\n---------\n\nCo-authored-by: Dan Pupius <dan@pupi.us>",
"is_bot": false,
"headline": "fix(container): harden Apple async container ops (network delete + se…",
"author_name": "Andrew Bezzub",
"author_login": "abezzub-dr",
"committed_at": "2026-06-16T02:34:47Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "6e20317489091dce3c7cf0e2e932568428962392",
"body": "…(#366)\n\n* fix(run): default service version to registry default; add ministack\n\nService dependencies declared without an explicit version (e.g. `ministack`\nrather than `ministack@latest`) produced an empty image tag, so the runtime\nrejected the reference with \"invalid reference format\". buildServic\n[…]\n\n`latest` tag, making runs non-reproducible. Pin to the 1.3 minor tag (a\npublished floating-patch tag) and update the dependencies reference table.\n\n---------\n\nCo-authored-by: Dan Pupius <dan@pupi.us>",
"is_bot": false,
"headline": "fix(run): default service version to registry default; add ministack …",
"author_name": "Andrew Bezzub",
"author_login": "abezzub-dr",
"committed_at": "2026-06-16T01:44:40Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "80036aa84e60412354f6f061183d10d0d4481d0e",
"body": "…(#376)\n\n* fix(github): use Basic auth for github.com git smart-HTTP over HTTPS\n\nHTTPS git fetch/push to github.com failed with only the `github` grant due\nto two stacked issues:\n\n1. The provider injected `Authorization: Bearer <token>` for github.com, but\n GitHub's git smart-HTTP endpoints (info/\n[…]\nntity case.\n\n* style(run): move proxyAuthMethod-chain comment above struct literal\n\nKeep the ImageSpec field alignment uniform (gofmt splits alignment runs at an\ninterior comment). No behavior change.",
"is_bot": false,
"headline": "fix(github): use Basic auth for github.com git smart-HTTP over HTTPS …",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-16T01:34:45Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "e1fb7ed016cd96453102230d321dd0937691a135",
"body": "* fix(claude): install python by default for the Claude agent\n\nClaude Code's security-guidance feature shells out to python3, but the\ngenerated image for the Claude agent had no Python interpreter, so it\nreported `Failed with non-blocking status code: /bin/sh: 1: python3: not\nfound`.\n\nRunning the Cl\n[…]\nblock so\nthe two comments stay associated with their own functions. As inserted, the\ncontiguous comment block was treated by Go as the doc for the wrong function,\nleaving hostGitIdentity undocumented.",
"is_bot": false,
"headline": "fix(claude): install python by default for the Claude agent (#371)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-15T16:09:01Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "e051df6f6c6d035408e660ecf7d24f0857ae8a83",
"body": null,
"is_bot": false,
"headline": "docs: changelog for v0.5.4 (#365)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-06-01T18:25:17Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4c689f3b7a4cc5a65e5b07664f63f6c38828b5ad",
"body": "* fix(claude): preserve source file mode in marketplace tar\n\nThe host-side marketplace tar in CollectMarketplaceTar wrote every file\nheader with a hardcoded Mode: 0644, so executable hook scripts (e.g.\nbin/aw-hook, scripts/on-prompt-submit.sh) extracted at 0644 in the\ncontainer and failed with \"Perm\n[…]\n before \"tar xf\", so emitting a \"./\"\nheader only chmod'd the destination to the host temp-clone-dir mode\n(0700 from os.MkdirTemp) on extraction.\n\n---------\n\nCo-authored-by: Daniel Pupius <dan@pupi.us>",
"is_bot": false,
"headline": "fix(claude): preserve source file mode in marketplace tar (#363)",
"author_name": "Andrew Bezzub",
"author_login": "abezzub-dr",
"committed_at": "2026-05-31T16:27:40Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "7e287bc6a7d15d6ccac7340d8fc879ef21392dce",
"body": "* fix(claude): match Claude Code's project-dir slug rule\n\nWorkspaceToClaudeDir only replaced \"/\" with \"-\", but Claude Code\nslugifies project directories by replacing every non-alphanumeric\ncharacter with \"-\" (verified against the claude binary v2.1.156).\n\nFor any workspace path containing a \".\" (e.g\n[…]\nalready map to \"-\", so it never changed output.\n- Correct the UTF-16 doc note: only characters above U+FFFF (surrogate\n pairs) diverge from Claude Code; BMP non-ASCII maps to one \"-\" on both\n sides.",
"is_bot": false,
"headline": "fix(claude): match Claude Code's project-dir slug rule (#364)",
"author_name": "Andrew Bezzub",
"author_login": "abezzub-dr",
"committed_at": "2026-05-31T16:26:20Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "7674d466cad4922108c319baf8bc78fcd043fa7c",
"body": "… (#362)\n\n* fix(tui): drain vt emulator reply pipe to prevent compositor deadlock\n\nWhen the child inside the container emitted any terminal query that\nrequired a reply (CSI c Primary Device Attributes, CSI 6n cursor\nposition, etc.), moat's compositor froze on the first paint. From the\nuser's perspec\n[…]\npositorLocked: replace a stale reference to a never-defined\n\"stopCompositorLocked\" with the real call sites (closeEmulatorReplyPipe,\ninvoked from exitCompositorLocked / Reset / Cleanup). Greppability.",
"is_bot": false,
"headline": "fix(tui): drain vt emulator reply pipe to prevent compositor deadlock…",
"author_name": "Andrew Bezzub",
"author_login": "abezzub-dr",
"committed_at": "2026-05-28T21:35:36Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "ed74bcda482840d245c5ae57f3a98da34c218e50",
"body": "ci: bump actions to Node 24 majors\n\nNode 20 is being forced off GitHub Actions runners (June 2 2026), and the\nrelease run flagged the deprecation. Bump the Node-20 JavaScript actions to\ntheir first/current Node-24 majors:\n\n- actions/checkout v4 -> v6\n- actions/setup-go v5 -> v6\n- goreleaser/goreleas\n[…]\n Node 20; v9 keeps the\n 'version' input, so golangci-lint stays pinned to v2.8.0)\n\nbats-core/bats-action and anthropics/claude-code-action are composite actions\n(not affected) and are left unchanged.",
"is_bot": false,
"headline": "ci: bump GitHub Actions to Node 24 majors (#361)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-05-26T03:41:22Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "4b07278024601ee4edfe755162fbb918c0390d22",
"body": "docs: changelog for v0.5.3 and backfill v0.5.2\n\nCut v0.5.3 (#353, #355, #357, #358) from Unreleased, and backfill the\nv0.5.2 section (#345, #349, #351, #352) which was tagged on 2026-05-18 but\nnever written up.",
"is_bot": false,
"headline": "docs: changelog for v0.5.3 (and backfill v0.5.2) (#360)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-05-25T22:52:30Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "33b7afb364d4372619da188fe4ad82720e7ab0a5",
"body": "* fix(claude): don't scrape claude setup-token output\n\nmoat grant claude spawned `claude setup-token` under a PTY, captured\nits output, and parsed the OAuth token out of it. Recent Claude CLI\nversions render setup-token as a TUI, so the token never appeared\ncontiguously in the captured stream and ex\n[…]\nste prompt from the claude setup-token output with a\nui.Section header, and drop the now-redundant prompt line in the\npaste-existing-token flow.\n\n---------\n\nCo-authored-by: Daniel Pupius <dan@pupi.us>",
"is_bot": false,
"headline": "fix(claude): don't scrape claude setup-token output (#353)",
"author_name": "Nate Hardison",
"author_login": "natehardison",
"committed_at": "2026-05-25T22:49:35Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "19dd4eb422dd2aedfc14b6e248c0051aadf4bbec",
"body": "docs: drop 2.1.150 workaround framing from version-pinning changelog entry",
"is_bot": false,
"headline": "docs: simplify version-pinning changelog entry (#359)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-05-25T22:00:43Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a3eea8eb833a413ea8c19787dc9a52c67533ae8d",
"body": "…ls (#358)\n\n* fix(claude): write subscriptionType and scopes to container credentials\n\nClaude Code in the container showed 'not logged in' / 'API Usage Billing'\nbecause the generated ~/.claude/.credentials.json had null scopes and no\nsubscriptionType. Claude Code treats such a session as unauthentic\n[…]\nuggestion — a closed set would\nreject valid future plan names; the field is documented and the server\nenforces the real plan.)\n\n* docs(claude): note why oauthToken.Scopes has no omitempty (review FYI)",
"is_bot": false,
"headline": "fix(claude): write subscriptionType and scopes to container credentia…",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-05-25T21:47:44Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "66bc44f063e7d05339a3d4ae5329eb31ec73bc18",
"body": "* build(lint): exclude SA5011 false positives in test files\n\ngolangci-lint v2.8.0's bundled staticcheck does not recognize\nt.Fatal/t.Fatalf as terminating, so it flags nil-guarded dereferences\nin tests (if x == nil { t.Fatal(...) }; x.Field) as possible nil\ndereferences. Exclude SA5011 in _test.go f\n[…]\n\nagent: claude-code injects an unversioned dependency that intentionally\ninstalls latest; the version-dropping bug only affected explicit\nclaude-code@VERSION pins, so the parenthetical was inaccurate.",
"is_bot": false,
"headline": "fix(deps): install the pinned claude-code version (#357)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-05-25T21:46:00Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "65f06f672d6c1b45aaac0982200b96de1b52b030",
"body": "…#355)\n\n* fix(container): set tmpfs mode to 1777 for non-root container users\n\nTmpfs mounts created via the Docker SDK without explicit TmpfsOptions\ninherit runc's default mode of 755 owned by root. Non-root container\nusers (e.g., the `moatuser` we run agents as) cannot write to such\nmounts, so `mou\n[…]\n WHY\n (the exec option for native binaries); drop the \"PR #355\" task reference\n in apple.go.\n- Delete narrative WHAT-only doc comments from the new tests; test names\n already state what's asserted.",
"is_bot": false,
"headline": "fix(container): set tmpfs mode to 1777 for non-root container users (…",
"author_name": "Andrew Bezzub",
"author_login": "abezzub-dr",
"committed_at": "2026-05-25T16:11:54Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "3ecc34a399dfee0c561612f5368e30a4b36806a1",
"body": "…EN env (#351)\n\n* fix(claude): use sk-ant-oat01 placeholder, drop CLAUDE_CODE_OAUTH_TOKEN env\n\nClaude Code checks the sk-ant-oat prefix to decide whether the session is\nOAuth-authenticated. With the previous CLAUDE_CODE_OAUTH_TOKEN=moat-proxy-injected\nenv var, Claude Code did not recognize the sessi\n[…]\ntContainer, monitorWg.Wait blocks until captureLogs and\ncleanupResources finish, and only then does t.TempDir() proceed.\n\nReproduced 6/20 failures without the fix; 100 race-enabled runs pass\nafter it.",
"is_bot": false,
"headline": "fix(claude): use sk-ant-oat01 placeholder, drop CLAUDE_CODE_OAUTH_TOK…",
"author_name": "Andrew Bezzub",
"author_login": "abezzub-dr",
"committed_at": "2026-05-18T21:52:08Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "223bce5370c82e6edc2e139fff4f91e5fb58823b",
"body": "Setup-token grants don't set ExpiresAt on the credential, leaving it as\nthe zero time.Time. WriteCredentialsFile called UnixMilli() on this,\nproducing -62135596800000 (year 0001) in .credentials.json. Claude Code\nread that as an expired credential, showing \"not logged in\" and\n\"API Usage Billing\" in \n[…]\nyear-ahead timestamp when ExpiresAt is zero. Setup-tokens are\nlong-lived and the placeholder credential just needs to look valid\nlocally — the real token is injected by the proxy at the network layer.",
"is_bot": false,
"headline": "fix(claude): use far-future expiry for setup-token credentials (#352)",
"author_name": "Andrew Bezzub",
"author_login": "abezzub-dr",
"committed_at": "2026-05-18T15:44:47Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "4568fc818656f1363ea6462e29669d037dbc4395",
"body": "… (#345)\n\nMarketplace entries like {source: github, repo: owner/repo} were being\nrewritten to {source: git, url: https://github.com/owner/repo.git} in\nLoadSettings, LoadKnownMarketplaces, and ConfigToSettings before being\nwritten into the container's settings.json and known_marketplaces.json.\n\nWhen \n[…]\nMarketplace, `claude plugin marketplace add`) already accept either\nform, so no changes are needed there.\n\nUpdate existing tests that locked in the old normalized output to assert\nthe preserved shape.",
"is_bot": false,
"headline": "fix(claude): preserve marketplace source shape for allowlist matching…",
"author_name": "Andrew Bezzub",
"author_login": "abezzub-dr",
"committed_at": "2026-05-18T15:43:51Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "66febdb4e0430595df9a313efe984cdeae74e344",
"body": "* fix(tui): keep footer pinned when child resets scroll region\n\nChildren like Claude Code (via Ink) defensively emit ESC[r at startup\nto reset DECSTBM. That undid moat's scroll region, so every newline at\nthe bottom row scrolled the footer into scrollback and the 50ms\ndebounced redraw stamped a fres\n[…]\ns form would pass\nif interception double-emitted or skipped the replacement; the count\nmakes the contract explicit. Matches the pattern already used in\nTestWriter_InterceptsDECSTBM_MultipleInOneWrite.",
"is_bot": false,
"headline": "fix(tui): keep footer pinned when child resets scroll region (#349)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-05-13T18:59:06Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "fc0596858df7275a341e3ca195860cd773c4e564",
"body": "* docs: changelog for v0.5.1\n\n* docs: track patch releases in changelog",
"is_bot": false,
"headline": "docs: changelog for v0.5.1 (#347)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-04-28T22:13:38Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b8afc8e91efc9fe086fb00390564baf1cdf700e7",
"body": "…#344)\n\nTestRegistryGithubBinaryURLsExist hits real GitHub release URLs to verify\nasset names. Transient 5xx responses and network errors were being reported\nas test failures, breaking CI on every GitHub blip (e.g. ripgrep arm64 502\non main, run 25020206997).\n\nOnly fail on 404/410 (asset genuinely missing) and other 4xx (real config\nproblems). Skip on 5xx and transport errors. Update the test comment to\nmatch actual behavior — it claimed to be opt-in via -urls, but only\nhonored testing.Short.",
"is_bot": false,
"headline": "test(deps): skip transient failures in github URL reachability test (…",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-04-27T22:02:04Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "fb8a324a2881d8afbfd3d1406cebd0a14452e22d",
"body": "* docs(plans): tui debug dump and reset design + plan\n\n* refactor(trace): extract EventRecorder interface\n\n* feat(trace): add bounded RingRecorder for on-demand dumps\n\n* test(trace): assert FIFO order in RingRecorder eviction\n\n* feat(term): add ctrl+/ d and r escape actions for TUI debug\n\n* docs(ter\n[…]\n\n- internal/term/inject_test.go: drop the timing-dependent 10ms sleep in\n TestInjectableReader_CloseUnblocksInject; the test contract holds\n regardless of whether Inject parks before or after Close.",
"is_bot": false,
"headline": "feat(tui): add ctrl+/ d (dump) and r (reset) shortcuts (#343)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-04-27T21:21:26Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "3cbb24159b8eab60a4df6b97efe6278dc793951a",
"body": "* fix(run): prevent Close() deadlock when WaitContainer blocks (#315)\n\nmonitorContainerExit used context.Background() for WaitContainer, so\nClose()'s monitorWg.Wait() deadlocked when Docker was slow to report\ncontainer exit (common with custom networks in service tests).\n\nAdd a dedicated monitorCtx \n[…]\nhe run dir if Create() fails after MkdirAll. Without this,\n failures during proxy/credential/container setup leave empty\n ~/.moat/runs/<id>/ dirs that don't surface in `moat list` or\n `moat clean`.",
"is_bot": false,
"headline": "fix(run): bound network create and reap orphan moat networks (#342)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-04-26T03:16:59Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "9fc790d34612dd09b23482d83e184b9a5d0faf54",
"body": "…336)\n\nfix: point capability-mismatch errors at the real command\n\nTwo error paths told users to run 'moat proxy restart' when the daemon\nlacked a required capability, but there is no 'restart' subcommand —\ncobra falls through to status and silently does nothing. Replace with\n'moat proxy stop' and note that the next command will spawn a fresh\ndaemon.",
"is_bot": false,
"headline": "fix: correct error message to suggest command that actually exists (#…",
"author_name": "Andrew Bezzub",
"author_login": "abezzub-dr",
"committed_at": "2026-04-25T00:08:04Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4c57090257b8bb9b7ccc37291de7753984c9e915",
"body": "* fix(proxy): reach host from custom networks on Docker Desktop\n\nOn Docker Desktop (macOS/Windows), moat resolves the synthetic\n\"moat-proxy\" and \"moat-host\" names via --add-host:host-gateway. Docker\nsubstitutes the docker0 bridge gateway IP (e.g. 172.17.0.1), which is\nunreachable from containers on \n[…]\n env path to document how the\n helper composes sentinel output when GetHostAddress() ever returns\n \"\". moat-init.sh fails closed on the unresolvable empty hostname,\n which is the intended behavior.",
"is_bot": false,
"headline": "fix(proxy): reach host from custom networks on Docker Desktop (#337)",
"author_name": "Andrew Bezzub",
"author_login": "abezzub-dr",
"committed_at": "2026-04-25T00:07:38Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "0d6c955ae05f0f6ce5b997f39d0cc75f1029ea68",
"body": "* fix(deps): handle multi-line YAML block scalars in build hooks\n\nMulti-line strings from YAML block scalars (pipe |) in post_build and\npost_build_root hooks produced invalid Dockerfiles because raw newlines\nwere interpolated directly into RUN commands.\n\nAdd formatHookCommand() to join non-empty lin\n[…]\n\n\n* fix(deps): guard against whitespace-only hook strings\n\nUse formatHookCommand's return value to skip empty hooks, preventing\ninvalid \"RUN \\n\" in the Dockerfile when a hook contains only whitespace.",
"is_bot": false,
"headline": "fix(deps): handle multi-line YAML block scalars in build hooks (#339)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-04-24T22:36:07Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "cfc5f2e149eeabf7f07d09000bbf58fa7a1617bf",
"body": "* fix(run): auto-include MCP auth grants in credential loading\n\nMCP servers configured with auth.grant in moat.yaml had their\ncredentials validated but never loaded into the RunContext. The grant\nnames were checked by validateMCPGrants but not added to the list that\nthe credential processing loop in\n[…]\nredential): add tests for validateProvider path traversal guard\n\nCover forward slash, backslash, dot-dot traversal, and absolute paths.\nAlso verify Get, Save, and Delete all reject traversal attempts.",
"is_bot": false,
"headline": "fix(run): auto-include MCP auth grants in credential loading (#338)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-04-24T22:34:43Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "616f1b3464b227207b956b8205f8de16fdc916e1",
"body": "* ci(e2e): use setsid + process-group kill to prevent orphan hangs\n\nPrevious timeout approaches all failed because Docker child processes\nspawned by E2E tests kept the step alive:\n- tee pipe: Docker children inherited pipe FDs, keeping tee alive\n- timeout(1): only kills the direct child, not grandch\n[…]\neplace inline CI detection checks and the one-off skipHostTrafficOnCI\nwith a shared skipIfCI(t, reason) helper in e2e_test.go, alongside the\nexisting skipIfNoAppleContainer and skipIfNoDocker helpers.",
"is_bot": false,
"headline": "fix(e2e): skip host traffic tests that freeze CI runner (#332)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-04-21T17:55:36Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "9d8a460035d4c623b12199825a77c54e03ca723d",
"body": "* refactor: extract gatekeeper and proxy to github.com/majorcontext/gatekeeper\n\nMove internal/proxy/ and internal/gatekeeper/ to the new standalone\nrepository. Moat now imports the proxy package as an external dependency.\n\nRemoved from this repo:\n- internal/proxy/ (TLS-intercepting proxy)\n- internal\n[…]\ngatekeeper module repo instead of deleted internal/proxy path.\n\n* docs: remove stale proxy/ entry from CLAUDE.md directory tree\n\nThe directory no longer exists locally — it's in the gatekeeper module.",
"is_bot": false,
"headline": "refactor: extract gatekeeper and proxy to standalone repo (#333)",
"author_name": "Andy Bonventre",
"author_login": "andybons",
"committed_at": "2026-04-20T17:58:09Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "d0c239739d586e4ac5b4840d7dc21ca4334587bb",
"body": "ci(e2e): use shell timeout to guarantee test process is killed\n\nGitHub Actions timeout-minutes (both step and job level) failed to fire\nafter 50+ minutes, likely because the process was blocked in kernel\nspace (Docker operations). Neither the 20-minute step timeout nor the\n45-minute job timeout trig\n[…]\nils `timeout` as the primary kill mechanism:\n- SIGTERM at 18 minutes, SIGKILL 30 seconds later\n- `|| true` ensures the step exits 0 so the upload step runs\n- GitHub timeouts kept as backup safety nets",
"is_bot": false,
"headline": "ci(e2e): use shell timeout to guarantee process kill (#331)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-04-18T00:46:57Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "521e5a727d5d5b13eb0a522505b7ddf4ad5c3069",
"body": "ci(e2e): add step-level timeout so artifact upload runs after test kill\n\nGitHub Actions job-level timeout-minutes kills the entire job without\nrunning if:always() steps. This meant the tee'd output file was never\nuploaded as an artifact, giving us zero diagnostic output.\n\nAdd a 20-minute step-level \n[…]\nmeout to 45 minutes as a safety net.\n\nTimeout layering:\n- 15m: Go -test.timeout panics with goroutine stacks\n- 20m: Step timeout kills the process, job continues\n- 45m: Job timeout as final safety net",
"is_bot": false,
"headline": "ci(e2e): add step-level timeout so artifact upload runs (#330)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-04-17T23:32:35Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "9fdb9a37902c54139f4ba306740f3d9571341e79",
"body": "…329)\n\nThe E2E tests hang on CI but produce zero diagnostic output because:\n1. go test compiles the test binary before running it, and this\n compilation phase has no output and is not covered by -timeout\n2. GitHub Actions discards output from steps killed by timeout-minutes\n\nFix by pre-compiling t\n[…]\nest binary alongside the moat binary, running\nthe binary directly (skipping the go test compilation wrapper), piping\noutput through tee, and uploading the output file as an artifact with\nif: always().",
"is_bot": false,
"headline": "fix(ci): pre-compile E2E test binary and capture output on timeout (#…",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-04-17T22:16:03Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "27566bb090e6a652406230646586449f110b24a3",
"body": "…rking (#327)\n\n* fix(proxy): remove localhost/127.0.0.1 from NO_PROXY to close loopback bypass\n\nUnder Docker host-network mode, containers share the host loopback.\nHaving localhost and 127.0.0.1 in NO_PROXY let container processes\nconnect to host services directly, bypassing the proxy and the\nnetwor\n[…]\n proxy for network.host enforcement\n- bridge/Apple mode: loopback kept in NO_PROXY since the container's\n localhost is private and intra-container traffic should not be proxied\n\n* chore: retrigger CI",
"is_bot": false,
"headline": "fix(proxy): close loopback bypass in NO_PROXY under Docker host netwo…",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-04-17T21:34:47Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "7c3393b869ce3f4edda1f10969a8ab04c120a0c0",
"body": "The E2E test suite has been hanging on CI since April 15 with zero\noutput for ~2 hours until the GitHub Actions default timeout kills it.\n\nRoot cause: TestMain builds the moat binary via `go build` before any\ntests run, which produces no stdout. Without `-v`, `go test` buffers\nall output, so CI show\n[…]\n so TestMain skips its internal build\n- Add `-v` to stream test output in real time\n- Add `timeout-minutes: 30` to the job to prevent 6-hour hangs\n- Add progress messages in TestMain for debuggability",
"is_bot": false,
"headline": "fix(ci): prevent E2E test hang on CI runners (#328)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-04-17T21:34:19Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "142ff7905a47cefa52dbc3c0193ab8b0e36bac41",
"body": "* test(proxy): close coverage gaps for host-traffic proxy path\n\nAdd integration tests verifying that loopback bypass aliases (localhost,\n127.0.0.1, ::1) are blocked when HostGateway is \"moat-host\", for both\nHTTP and CONNECT request paths. Also add a test confirming allowed ports\nwork through aliases\n[…]\nly-return path as\nMoatHost since addProxyPortForLoopback returns immediately when gateway\nis not 127.0.0.1. Replace it with a test that verifies the actual dedup\nloop with multiple pre-existing ports.",
"is_bot": false,
"headline": "test(proxy): close coverage gaps for host-traffic proxy path (#326)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-04-17T00:58:55Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "a60349fb225025882b5982baa42d142a465ac197",
"body": "…e (#325)\n\n* fix(proxy): prevent ip6tables hang on hosts without IPv6 kernel module\n\nUse -w 5 (5-second timeout) for ip6tables instead of bare -w (wait\nforever). On CI hosts and containers where the ip6_tables kernel module\nis absent, ip6tables blocks indefinitely on the xtables lock, hanging\nthe en\n[…]\ne, add CHANGELOG\n\nClean up any partially-installed ip6tables rules if the chain fails\nmid-way, preventing the container from being left with an incomplete\npolicy (e.g. ACCEPT lo without a final DROP).",
"is_bot": false,
"headline": "fix(proxy): prevent ip6tables hang on hosts without IPv6 kernel modul…",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-04-17T00:18:56Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "be5572009bad40993b80bf5dc1bd82c0d6414803",
"body": "* fix(proxy): install ip6tables rules to block IPv6 egress bypass\n\nMirror all iptables OUTPUT chain rules with ip6tables equivalents in\nboth Docker and Apple container runtimes. Without this, containers on\ndual-stack hosts could bypass network.policy: strict by using IPv6\naddresses (e.g. curl -6).\n\n\n[…]\nention IPv6 coverage\n- Add ICMPv6 comment explaining intentional full-block behavior\n- Add CHANGELOG security entry for the IPv6 bypass fix\n\n* fix(proxy): tighten ip6tables-legacy comment in docker.go",
"is_bot": false,
"headline": "fix(proxy): install ip6tables rules to block IPv6 egress bypass (#324)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-04-17T00:04:45Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "7af31ca27613c4940024c8e16fcd5987ca35618f",
"body": "* feat(config): honor MOAT_HOME to relocate moat state directory\n\nIntroduce MOAT_HOME as the single override for the moat configuration\ndirectory. When set, it replaces ~/.moat as the root for runs,\ncredentials, daemon socket/lock, keyring key file, and per-run sockets.\nThird-party state (~/.claude,\n[…]\non it produced garbled output like \"file (/home/user/.moat\".\nUse a type assertion on the concrete backend to get the raw path; fall back\nto a generic label when the fallback backend is something else.",
"is_bot": false,
"headline": "feat(config): honor MOAT_HOME to relocate moat state directory (#323)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-04-16T22:03:02Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "d707c86eb6952c6c7acf6c38f7e7578368f2deeb",
"body": "* fix(proxy): prevent host traffic from bypassing proxy via NO_PROXY\n\nMOAT_HOST_GATEWAY was included in NO_PROXY on all platforms, causing\nhost-bound traffic to bypass the proxy entirely. The proxy's\nisHostGateway check never fired, so network.host port restrictions\nwere not enforced.\n\nIntroduce syn\n[…]\n\n\nlen(opts.Config.MCP) > 0 already triggers needsProxyForConfig for any\nMCP entry, so the subsequent loop checking mcp.Policy != nil is\nunreachable — the && branch was redundant with the preceding ||.",
"is_bot": false,
"headline": "fix(proxy): prevent host traffic from bypassing proxy (#321)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-04-16T19:11:54Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "7331bf98d8952e659890a880554589be95b02c3d",
"body": "- Add Python 3.13 and 3.14 to the supported versions list\n- Bump uv default from 0.5.14 to 0.11.6\n\nPython 3.13 and 3.14 are now widely used — several projects require\nthem (e.g. `requires-python = \">=3.14\"`). The old uv 0.5.14 doesn't\nsupport features like `exclude-newer = \"14 days\"` (relative dates,\nadded in uv 0.7+).",
"is_bot": false,
"headline": "feat(deps): add Python 3.13/3.14 and bump uv to 0.11.6 (#316)",
"author_name": "Ted Mao",
"author_login": "ternarybits",
"committed_at": "2026-04-14T23:33:46Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c45b5d9bb0e945c04a2c80c4157676e812ec9639",
"body": "* ci(release): add workflow_dispatch for manual gatekeeper image builds\n\nAllow triggering the release workflow manually with a tag input.\nGoReleaser is skipped on manual dispatch; only the gatekeeper image\njob runs, checking out the specified tag.\n\n* ci(release): pass tag input to metadata-action for semver tags\n\nWithout this, workflow_dispatch uses github.ref (the branch) instead\nof the tag input, so semver tags aren't generated.",
"is_bot": false,
"headline": "ci(release): add workflow_dispatch for manual gatekeeper builds (#314)",
"author_name": "Andy Bonventre",
"author_login": "andybons",
"committed_at": "2026-04-13T18:05:52Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "aa82623cb80d75855b424eff3e552c4ecf08a4f8",
"body": "* ci(release): publish gatekeeper image to GHCR on tag push\n\nAdd a gatekeeper-image job to the release workflow that builds\ncmd/gatekeeper/Dockerfile and pushes to ghcr.io/majorcontext/moat-gatekeeper\nwith semver and SHA tags.\n\n* ci(release): address review — scope permissions, add multi-arch and ca\n[…]\nase gets contents:write,\n gatekeeper-image gets contents:read + packages:write\n- Add setup-buildx-action and build for linux/amd64,linux/arm64\n- Add GHA layer cache (cache-from/to type=gha, mode=max)",
"is_bot": false,
"headline": "ci(release): publish gatekeeper image to GHCR (#313)",
"author_name": "Andy Bonventre",
"author_login": "andybons",
"committed_at": "2026-04-13T17:52:57Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "c9ee1be4bb3a312f325b12b6b7fe048e31139267",
"body": "RuntimeApple can succeed on hosts with Apple containers. Use a\nnonexistent runtime type that always fails NewRuntimeByType.",
"is_bot": false,
"headline": "fix(test): use fake runtime type in unavailable cache test (#312)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-04-13T03:25:45Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "13ca67ecdf79881a266cbd796a3559b7573ea100",
"body": "* feat(container): add RuntimePool for multi-runtime support\n\nIntroduces RuntimePool, a thread-safe pool that manages multiple container\nruntime instances keyed by RuntimeType. Runtimes are lazily initialized\non first access. Includes NewRuntimeByType factory and ForEachAvailable\nfor querying all av\n[…]\nntime's running containers.\n\n* test(pool): add test for unavailable runtime caching\n\nVerify that a failed Get() populates the unavailable map and\nsubsequent calls return from cache without re-probing.",
"is_bot": false,
"headline": "feat: multi-runtime manager for cross-engine CLI commands (#311)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-04-13T03:10:31Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "2c3f51ee4f7e9822befbaf58065cbf2b86a50f69",
"body": "* fix(run): stop reconciliation from corrupting persisted run state\n\nRead-only commands like `moat status` and `moat list` were permanently\noverwriting metadata.json for cross-runtime runs, marking live containers\nas stopped. This happened because reconciliation used a single runtime to\ncheck all co\n[…]\nnal runs are caught early with stateConfirmed=true).\n\nFix goroutine leak in TestLoadPersistedRunsPreservesStateOnContainerError\nby documenting the intentional blocking behavior and using os.MkdirTemp.",
"is_bot": false,
"headline": "fix(run): stop reconciliation from corrupting persisted run state (#309)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-04-10T21:47:33Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "094f3c3b51d307854c820b37a3d48b50f9e34ba9",
"body": "* docs: changelog for v0.5.0\n\n* docs: address review feedback on v0.5.0 changelog",
"is_bot": false,
"headline": "docs: changelog for v0.5.0 (#307)",
"author_name": "Daniel Pupius",
"author_login": "dpup",
"committed_at": "2026-04-07T17:53:24Z",
"body_truncated": false,
"is_coding_agent": false
}
],
"releases_count": 14,
"commits_last_year": 532,
"latest_release_at": "2026-06-19T03:35:58Z",
"latest_release_tag": "v0.6.1",
"releases_from_tags": false,
"days_since_last_push": 2,
"active_weeks_last_year": 25,
"days_since_latest_release": 36,
"mean_days_between_releases": 11.7
},
"community": {
"has_readme": true,
"has_license": true,
"has_description": true,
"has_contributing": true,
"health_percentage": 50,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": false
},
"ecosystem": {
"packages": [
{
"name": "github.com/majorcontext/moat",
"exists": true,
"license": null,
"keywords": [],
"ecosystem": "go",
"matches_repo": true,
"registry_url": "https://pkg.go.dev/github.com/majorcontext/moat",
"is_deprecated": false,
"latest_version": "v0.6.1",
"repository_url": "https://github.com/majorcontext/moat",
"versions_count": 14,
"total_downloads": null,
"dependents_count": null,
"deprecation_note": null,
"maintainers_count": null,
"monthly_downloads": null,
"first_published_at": null,
"latest_published_at": "2026-06-19T03:32:08Z",
"latest_version_yanked": null,
"days_since_latest_publish": 36
}
]
},
"popularity": {
"forks": 11,
"stars": 44,
"watchers": 0,
"fork_history": {
"days": [
{
"date": "2026-03-05",
"count": 1
},
{
"date": "2026-03-07",
"count": 1
},
{
"date": "2026-03-09",
"count": 1
},
{
"date": "2026-03-16",
"count": 1
},
{
"date": "2026-03-19",
"count": 1
},
{
"date": "2026-03-30",
"count": 1
},
{
"date": "2026-04-09",
"count": 1
},
{
"date": "2026-04-14",
"count": 1
},
{
"date": "2026-05-19",
"count": 1
},
{
"date": "2026-06-13",
"count": 1
},
{
"date": "2026-07-07",
"count": 1
}
],
"complete": true,
"collected": 11,
"total_forks": 11
},
"star_history": null,
"open_issues_and_prs": 21
},
"ai_readiness": {
"has_nix": false,
"example_dirs": [
"examples"
],
"has_llms_txt": false,
"has_dockerfile": true,
"has_mcp_signal": false,
"bootstrap_files": [
"Makefile"
],
"api_schema_files": [],
"has_devcontainer": false,
"typecheck_configs": [],
"toolchain_manifests": [
"examples/language-server/go.mod",
"go.mod"
],
"largest_source_bytes": 108328,
"source_files_sampled": 543,
"oversized_source_files": 6,
"agent_instruction_files": [
"CLAUDE.md"
],
"agent_instruction_max_bytes": 14031
},
"dependencies": {
"manifests": [
"go.mod"
],
"advisories": {
"error": null,
"scope": null,
"source": null,
"findings": [],
"collected": false,
"malicious": [],
"truncated": false,
"by_severity": {},
"advisory_count": 0,
"affected_count": 0,
"assessed_count": 0,
"malicious_count": 0,
"assessed_package": null,
"unassessed_count": 0,
"direct_affected_count": 0
},
"ecosystems": [
"go"
],
"dependencies": [
{
"name": "github.com/aws/aws-sdk-go-v2",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.41.6"
},
{
"name": "github.com/aws/aws-sdk-go-v2/config",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.32.7"
},
{
"name": "github.com/aws/aws-sdk-go-v2/service/sts",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.41.6"
},
{
"name": "github.com/aymanbagabas/go-nativeclipboard",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.1.3"
},
{
"name": "github.com/charmbracelet/x/vt",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.0.0-20260127155452-b72a9a918687"
},
{
"name": "github.com/containerd/errdefs",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.0.0"
},
{
"name": "github.com/creack/pty",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.1.24"
},
{
"name": "github.com/docker/docker",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v28.5.2+incompatible"
},
{
"name": "github.com/docker/go-connections",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.6.0"
},
{
"name": "github.com/go-git/go-git/v5",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v5.17.1"
},
{
"name": "github.com/majorcontext/gatekeeper",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.13.0"
},
{
"name": "github.com/majorcontext/keep",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.6.0"
},
{
"name": "github.com/mattn/go-isatty",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.0.20"
},
{
"name": "github.com/moby/buildkit",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.28.1"
},
{
"name": "github.com/spf13/cobra",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.10.2"
},
{
"name": "github.com/stretchr/testify",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.11.1"
},
{
"name": "github.com/tonistiigi/fsutil",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.0.0-20251211185533-a2aa163d723f"
},
{
"name": "github.com/zalando/go-keyring",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.2.6"
},
{
"name": "golang.org/x/crypto",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.53.0"
},
{
"name": "golang.org/x/sync",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.21.0"
},
{
"name": "golang.org/x/sys",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.46.0"
},
{
"name": "golang.org/x/term",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.44.0"
},
{
"name": "gopkg.in/yaml.v3",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v3.0.1"
},
{
"name": "modernc.org/sqlite",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.43.0"
}
],
"all_dependencies": {
"error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
"source": null,
"packages": [],
"collected": false,
"truncated": false,
"total_count": null,
"direct_count": null,
"indirect_count": null
}
},
"maintainership": {
"issues": {
"open_prs": 4,
"merged_prs": 325,
"open_issues": 17,
"closed_ratio": 0.817,
"closed_issues": 76,
"closed_unmerged_prs": 22
},
"bus_factor": 1,
"bot_contributors": 1,
"top_contributors": [
{
"type": "User",
"login": "dpup",
"commits": 399,
"avatar_url": "https://avatars.githubusercontent.com/u/206453?v=4"
},
{
"type": "User",
"login": "andybons",
"commits": 100,
"avatar_url": "https://avatars.githubusercontent.com/u/365204?v=4"
},
{
"type": "User",
"login": "abezzub-dr",
"commits": 22,
"avatar_url": "https://avatars.githubusercontent.com/u/204732832?v=4"
},
{
"type": "User",
"login": "joonas",
"commits": 4,
"avatar_url": "https://avatars.githubusercontent.com/u/19793?v=4"
},
{
"type": "User",
"login": "mme",
"commits": 2,
"avatar_url": "https://avatars.githubusercontent.com/u/247775?v=4"
},
{
"type": "User",
"login": "daveworth",
"commits": 1,
"avatar_url": "https://avatars.githubusercontent.com/u/996477?v=4"
},
{
"type": "User",
"login": "natehardison",
"commits": 1,
"avatar_url": "https://avatars.githubusercontent.com/u/1433806?v=4"
},
{
"type": "User",
"login": "ternarybits",
"commits": 1,
"avatar_url": "https://avatars.githubusercontent.com/u/1718800?v=4"
},
{
"type": "User",
"login": "dmitriy-northbeam",
"commits": 1,
"avatar_url": "https://avatars.githubusercontent.com/u/182550476?v=4"
}
],
"contributors_sampled": 9,
"top_contributor_share": 0.751
},
"quality_signals": {
"has_ci": true,
"has_tests": true,
"ci_workflows": [
"ci.yml",
"claude-code-review.yml",
"claude.yml",
"release.yml"
],
"has_docs_dir": true,
"linter_configs": [
".golangci.yml"
],
"has_editorconfig": false,
"has_linter_config": true,
"has_precommit_config": false
},
"security_signals": {
"lockfiles": [
"go.sum"
],
"scorecard": {
"checks": [
{
"name": "Binary-Artifacts",
"score": 10,
"reason": "no binaries found in the repo",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
},
{
"name": "Branch-Protection",
"score": 5,
"reason": "branch protection is not maximal on development and all release branches",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
},
{
"name": "CI-Tests",
"score": null,
"reason": "internal error: internal error: Client.Repositories.ListStatuses: internal error: ListStatuses: GET https://api.github.com/repos/majorcontext/moat/commits/794e8429841f7301fa8cf3f8c748f8e14e35ace4/statuses: 504 We couldn't respond to your request in time. Sorry about that. Please try resubmitting your request and contact us if the problem persists. []",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
},
{
"name": "CII-Best-Practices",
"score": 0,
"reason": "no effort to earn an OpenSSF best practices badge detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
},
{
"name": "Code-Review",
"score": 1,
"reason": "Found 3/30 approved changesets -- score normalized to 1",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
},
{
"name": "Contributors",
"score": 10,
"reason": "project has 6 contributing companies or organizations",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
},
{
"name": "Dangerous-Workflow",
"score": 10,
"reason": "no dangerous workflow patterns detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
},
{
"name": "Dependency-Update-Tool",
"score": 0,
"reason": "no update tool detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
},
{
"name": "Fuzzing",
"score": 0,
"reason": "project is not fuzzed",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
},
{
"name": "License",
"score": 10,
"reason": "license file detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
},
{
"name": "Maintained",
"score": 10,
"reason": "30 commit(s) and 16 issue activity found in the last 90 days -- score normalized to 10",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
},
{
"name": "Packaging",
"score": 10,
"reason": "packaging workflow detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
},
{
"name": "Pinned-Dependencies",
"score": 1,
"reason": "dependency not pinned by hash detected -- score normalized to 1",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
},
{
"name": "SAST",
"score": 0,
"reason": "SAST tool is not run on all commits -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
},
{
"name": "Security-Policy",
"score": 0,
"reason": "security policy file not detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
},
{
"name": "Signed-Releases",
"score": 0,
"reason": "Project has not signed or included provenance with any releases.",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
},
{
"name": "Token-Permissions",
"score": 0,
"reason": "detected GitHub workflow tokens with excessive permissions",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
},
{
"name": "Vulnerabilities",
"score": 0,
"reason": "27 existing vulnerabilities detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
}
],
"commit": "616123618c8032ff42c3b6406aa6f4aba1ca0130",
"ran_at": "2026-07-26T01:54:22Z",
"aggregate_score": 3.9,
"scorecard_version": "v5.5.0"
},
"has_codeql_workflow": false,
"has_security_policy": false,
"has_dependabot_config": false
},
"contribution_flow": {
"collected": true,
"ci_last_run_at": "2026-07-23T21:44:26Z",
"oldest_open_prs": [
{
"number": 310,
"created_at": "2026-04-10T21:42:06Z",
"last_comment_at": "2026-04-14T23:46:07Z",
"last_comment_author": "claude"
},
{
"number": 354,
"created_at": "2026-05-19T19:25:26Z",
"last_comment_at": "2026-05-26T05:05:26Z",
"last_comment_author": "dpup"
},
{
"number": 441,
"created_at": "2026-07-17T21:15:55Z",
"last_comment_at": "2026-07-18T01:47:23Z",
"last_comment_author": "claude"
},
{
"number": 444,
"created_at": "2026-07-25T05:37:18Z",
"last_comment_at": null,
"last_comment_author": null
}
],
"last_merged_pr_at": "2026-07-17T05:07:20Z",
"ci_last_conclusion": "SKIPPED",
"oldest_open_issues": [
{
"number": 197,
"created_at": "2026-03-03T00:39:16Z",
"last_comment_at": "2026-03-31T19:45:20Z",
"last_comment_author": "joonas"
},
{
"number": 244,
"created_at": "2026-03-17T19:12:58Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 258,
"created_at": "2026-03-18T01:39:28Z",
"last_comment_at": "2026-03-18T19:40:36Z",
"last_comment_author": "dpup"
},
{
"number": 287,
"created_at": "2026-03-25T12:19:30Z",
"last_comment_at": "2026-04-08T18:55:40Z",
"last_comment_author": "abezzub-dr"
},
{
"number": 298,
"created_at": "2026-04-01T21:24:19Z",
"last_comment_at": "2026-04-03T21:53:35Z",
"last_comment_author": "dpup"
},
{
"number": 300,
"created_at": "2026-04-02T00:08:42Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 318,
"created_at": "2026-04-15T20:25:34Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 340,
"created_at": "2026-04-25T00:09:13Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 341,
"created_at": "2026-04-25T19:52:46Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 368,
"created_at": "2026-06-03T20:14:39Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 375,
"created_at": "2026-06-16T01:01:10Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 396,
"created_at": "2026-06-23T03:33:36Z",
"last_comment_at": "2026-07-23T21:44:22Z",
"last_comment_author": "dpup"
},
{
"number": 397,
"created_at": "2026-06-23T04:56:12Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 398,
"created_at": "2026-06-23T04:56:13Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 399,
"created_at": "2026-06-23T05:00:10Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 405,
"created_at": "2026-06-25T18:41:26Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 440,
"created_at": "2026-07-17T07:13:19Z",
"last_comment_at": null,
"last_comment_author": null
}
]
}
},
"config": {
"disabled_metrics": [],
"disabled_categories": [],
"disabled_components": {}
},
"source": {
"url": "https://github.com/majorcontext/moat",
"host": "github.com",
"name": "moat",
"owner": "majorcontext"
},
"metrics": {
"overall": {
"key": "overall",
"band": "moderate",
"name": "Overall health",
"note": null,
"notes": [],
"value": 66,
"inputs": {
"security": 39,
"vitality": 85,
"community": 51,
"governance": 61,
"engineering": 84
},
"components": []
},
"categories": [
{
"key": "vitality",
"band": "excellent",
"name": "Vitality",
"value": 85,
"weight": 0.22,
"metrics": [
{
"key": "development_activity",
"band": "good",
"name": "Development activity",
"note": null,
"notes": [],
"value": 81,
"inputs": {
"commits_last_year": 532,
"human_commit_share": 1,
"days_since_last_push": 2,
"active_weeks_last_year": 25
},
"components": [
{
"key": "push_recency",
"name": "Push recency",
"detail": "last push 2 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "push_recency",
"params": {
"days": 2
}
}
],
"max_points": 36
},
{
"key": "commit_cadence",
"name": "Commit cadence",
"detail": "25/52 weeks with commits",
"points": 17.3,
"status": "partial",
"details": [
{
"code": "commit_cadence_weeks",
"params": {
"weeks": 25
}
}
],
"max_points": 36
},
{
"key": "commit_volume",
"name": "Commit volume",
"detail": "532 commits in the last year",
"points": 18,
"status": "met",
"details": [
{
"code": "commits_last_year",
"params": {
"count": 532
}
}
],
"max_points": 18
},
{
"key": "openssf_scorecard_maintained",
"name": "OpenSSF Scorecard: Maintained",
"detail": "30 commit(s) and 16 issue activity found in the last 90 days -- score normalized to 10",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
},
{
"key": "release_discipline",
"band": "excellent",
"name": "Release discipline",
"note": null,
"notes": [],
"value": 90,
"inputs": {
"releases_count": 14,
"latest_release_tag": "v0.6.1",
"releases_from_tags": false,
"days_since_latest_release": 36,
"mean_days_between_releases": 11.7
},
"components": [
{
"key": "ships_releases",
"name": "Ships releases",
"detail": "14 releases published",
"points": 27,
"status": "met",
"details": [
{
"code": "releases_published",
"params": {
"count": 14
}
}
],
"max_points": 27
},
{
"key": "release_recency",
"name": "Release recency",
"detail": "latest release 36 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "release_recency",
"params": {
"days": 36
}
}
],
"max_points": 36
},
{
"key": "release_cadence",
"name": "Release cadence",
"detail": "a release every ~11.7 days",
"points": 27,
"status": "met",
"details": [
{
"code": "release_cadence",
"params": {
"gap": 11.7
}
}
],
"max_points": 27
},
{
"key": "openssf_scorecard_signed_releases",
"name": "OpenSSF Scorecard: Signed-Releases",
"detail": "Project has not signed or included provenance with any releases.",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "abandonment",
"band": "excellent",
"name": "Abandonment",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"cap": null,
"state": "maintained",
"guards": [],
"signals": [],
"red_flag": false,
"multiplier_pct": 100,
"declared_reason": null,
"unverified_reason": null,
"unanswered_open_prs": null,
"unanswered_open_issues": null,
"days_since_last_merged_pr": null,
"days_since_last_human_commit": 8,
"days_since_last_human_commit_is_floor": false
},
"components": [
{
"key": "project_is_still_maintained",
"name": "Project is still maintained",
"detail": "last human commit 8 days ago",
"points": 100,
"status": "met",
"details": [
{
"code": "abandonment_maintained",
"params": {
"days": 8
}
}
],
"max_points": 100
}
]
}
],
"description": "Is the project alive — is code being written and are releases shipping?"
},
{
"key": "community",
"band": "moderate",
"name": "Community & Adoption",
"value": 51,
"weight": 0.18,
"metrics": [
{
"key": "popularity",
"band": "at_risk",
"name": "Popularity & adoption",
"note": null,
"notes": [],
"value": 35,
"inputs": {
"forks": 11,
"stars": 44,
"watchers": 0,
"growth_state": "unverified",
"growth_factor_pct": 100,
"growth_unverified_reason": "no_history"
},
"components": [
{
"key": "stars",
"name": "Stars",
"detail": "44 stars",
"points": 26.5,
"status": "partial",
"details": [
{
"code": "stars",
"params": {
"count": 44
}
}
],
"max_points": 60
},
{
"key": "forks",
"name": "Forks",
"detail": "11 forks",
"points": 8.3,
"status": "partial",
"details": [
{
"code": "forks",
"params": {
"count": 11
}
}
],
"max_points": 25
},
{
"key": "watchers",
"name": "Watchers",
"detail": "0 watchers",
"points": 0,
"status": "missed",
"details": [
{
"code": "watchers",
"params": {
"count": 0
}
}
],
"max_points": 15
}
]
},
{
"key": "community_health",
"band": "good",
"name": "Community health",
"note": null,
"notes": [],
"value": 70,
"inputs": {
"has_readme": true,
"has_license": true,
"has_contributing": true,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": false
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 22.5,
"status": "met",
"details": [],
"max_points": 22.5
},
{
"key": "license",
"name": "License",
"detail": "recognized license (MIT)",
"points": 22.5,
"status": "met",
"details": [
{
"code": "license_standard",
"params": {}
},
{
"code": "license_spdx",
"params": {
"spdx": "MIT"
}
}
],
"max_points": 22.5
},
{
"key": "contributing_guide",
"name": "CONTRIBUTING guide",
"detail": null,
"points": 18,
"status": "met",
"details": [],
"max_points": 18
},
{
"key": "code_of_conduct",
"name": "Code of conduct",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 13.5
},
{
"key": "issue_template",
"name": "Issue template",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.2
},
{
"key": "pr_template",
"name": "PR template",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 6.3
}
]
}
],
"description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
},
{
"key": "governance",
"band": "moderate",
"name": "Sustainability & Governance",
"value": 61,
"weight": 0.24,
"metrics": [
{
"key": "maintainer_resilience",
"band": "at_risk",
"name": "Maintainer resilience (bus factor)",
"note": null,
"notes": [],
"value": 37,
"inputs": {
"bus_factor": 1,
"contributors_sampled": 9,
"top_contributor_share": 0.751
},
"components": [
{
"key": "bus_factor",
"name": "Bus factor",
"detail": "1 contributor(s) cover half of all commits",
"points": 9,
"status": "partial",
"details": [
{
"code": "bus_factor",
"params": {
"count": 1
}
}
],
"max_points": 54
},
{
"key": "commit_distribution",
"name": "Commit distribution",
"detail": "top contributor authored 75% of commits",
"points": 5.6,
"status": "partial",
"details": [
{
"code": "top_contributor_share",
"params": {
"share": 75
}
}
],
"max_points": 22.5
},
{
"key": "contributor_breadth",
"name": "Contributor breadth",
"detail": "9 contributors",
"points": 12.2,
"status": "partial",
"details": [
{
"code": "contributors_sampled",
"params": {
"count": 9
}
}
],
"max_points": 13.5
},
{
"key": "openssf_scorecard_contributors",
"name": "OpenSSF Scorecard: Contributors",
"detail": "project has 6 contributing companies or organizations",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
},
{
"key": "responsiveness",
"band": "good",
"name": "Issue & PR responsiveness",
"note": null,
"notes": [],
"value": 76,
"inputs": {
"merged_prs": 325,
"open_issues": 17,
"closed_issues": 76,
"issue_closed_ratio": 0.817,
"closed_unmerged_prs": 22
},
"components": [
{
"key": "issue_resolution",
"name": "Issue resolution",
"detail": "82% of issues closed",
"points": 38.2,
"status": "partial",
"details": [
{
"code": "issues_closed_share",
"params": {
"share": 82
}
}
],
"max_points": 46.75
},
{
"key": "pr_acceptance",
"name": "PR acceptance",
"detail": "325/347 decided PRs merged",
"points": 35.8,
"status": "partial",
"details": [
{
"code": "decided_prs_merged",
"params": {
"merged": 325,
"decided": 347
}
}
],
"max_points": 38.25
},
{
"key": "openssf_scorecard_code_review",
"name": "OpenSSF Scorecard: Code-Review",
"detail": "Found 3/30 approved changesets -- score normalized to 1",
"points": 1.5,
"status": "partial",
"details": [],
"max_points": 15
}
]
},
{
"key": "stewardship",
"band": "at_risk",
"name": "Ownership & stewardship",
"note": null,
"notes": [],
"value": 44,
"inputs": {
"followers": 7,
"owner_type": "Organization",
"is_verified": null,
"owner_login": "majorcontext",
"public_repos": 6,
"account_age_days": 186
},
"components": [
{
"key": "ownership_backing",
"name": "Ownership backing",
"detail": "organization-owned",
"points": 30,
"status": "met",
"details": [
{
"code": "owner_organization",
"params": {}
}
],
"max_points": 30
},
{
"key": "verified_domain",
"name": "Verified domain",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 20
},
{
"key": "owner_reach",
"name": "Owner reach",
"detail": "7 followers of majorcontext",
"points": 6.5,
"status": "partial",
"details": [
{
"code": "owner_followers",
"params": {
"count": 7,
"login": "majorcontext"
}
}
],
"max_points": 25
},
{
"key": "track_record",
"name": "Track record",
"detail": "6 public repos, account ~0 yr old",
"points": 7.2,
"status": "partial",
"details": [
{
"code": "public_repos",
"params": {
"count": 6
}
},
{
"code": "account_age_years",
"params": {
"years": 0
}
}
],
"max_points": 25
}
]
},
{
"key": "package_maintenance",
"band": "excellent",
"name": "Package maintenance",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"packages": [
"github.com/majorcontext/moat"
],
"ecosystems": "go",
"any_deprecated": false,
"min_days_since_publish": 36
},
"components": [
{
"key": "published_resolvable",
"name": "Published & resolvable",
"detail": "1 package(s) on go",
"points": 25,
"status": "met",
"details": [
{
"code": "packages_published",
"params": {
"count": 1,
"ecosystems": "go"
}
}
],
"max_points": 25
},
{
"key": "publish_recency",
"name": "Publish recency",
"detail": "latest publish 36 days ago",
"points": 35,
"status": "met",
"details": [
{
"code": "publish_recency",
"params": {
"days": 36
}
}
],
"max_points": 35
},
{
"key": "version_history",
"name": "Version history",
"detail": "14 published versions",
"points": 20,
"status": "met",
"details": [
{
"code": "published_versions",
"params": {
"count": 14
}
}
],
"max_points": 20
},
{
"key": "not_deprecated",
"name": "Not deprecated",
"detail": "active, not deprecated or yanked",
"points": 20,
"status": "met",
"details": [
{
"code": "package_not_deprecated",
"params": {}
}
],
"max_points": 20
}
]
}
],
"description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
},
{
"key": "engineering",
"band": "good",
"name": "Engineering Quality",
"value": 84,
"weight": 0.2,
"metrics": [
{
"key": "engineering_practices",
"band": "good",
"name": "Engineering practices",
"note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: CI-Tests. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"openssf_scorecard_ci_tests"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 80,
"inputs": {
"has_ci": true,
"has_tests": true,
"has_editorconfig": false,
"has_linter_config": true,
"has_precommit_config": false
},
"components": [
{
"key": "ci_workflows",
"name": "CI workflows",
"detail": "4 workflow(s)",
"points": 24,
"status": "met",
"details": [
{
"code": "ci_workflows",
"params": {
"count": 4
}
}
],
"max_points": 24
},
{
"key": "tests_present",
"name": "Tests present",
"detail": null,
"points": 24,
"status": "met",
"details": [],
"max_points": 24
},
{
"key": "linter_config",
"name": "Linter config",
"detail": ".golangci.yml",
"points": 16,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": ".golangci.yml"
}
}
],
"max_points": 16
},
{
"key": "pre_commit_hooks",
"name": "Pre-commit hooks",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 9.6
},
{
"key": "editorconfig",
"name": ".editorconfig",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 6.4
},
{
"key": "openssf_scorecard_ci_tests",
"name": "OpenSSF Scorecard: CI-Tests",
"detail": "internal error: internal error: Client.Repositories.ListStatuses: internal error: ListStatuses: GET https://api.github.com/repos/majorcontext/moat/commits/794e8429841f7301fa8cf3f8c748f8e14e35ace4/statuses: 504 We couldn't respond to your request in time. Sorry about that. Please try resubmitting your request and contact us if the problem persists. []",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 20
}
]
},
{
"key": "documentation",
"band": "excellent",
"name": "Documentation",
"note": null,
"notes": [],
"value": 90,
"inputs": {
"topics": [],
"has_wiki": true,
"homepage": "https://majorcontext.com/moat",
"has_readme": true,
"has_docs_dir": true,
"has_description": true
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 30,
"status": "met",
"details": [],
"max_points": 30
},
{
"key": "documentation_directory",
"name": "Documentation directory",
"detail": null,
"points": 25,
"status": "met",
"details": [],
"max_points": 25
},
{
"key": "documentation_homepage_site",
"name": "Documentation / homepage site",
"detail": "https://majorcontext.com/moat",
"points": 15,
"status": "met",
"details": [],
"max_points": 15
},
{
"key": "repository_description",
"name": "Repository description",
"detail": null,
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "topics",
"name": "Topics",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
},
{
"key": "wiki",
"name": "Wiki",
"detail": null,
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
}
],
"description": "Are baseline engineering and documentation practices in place?"
},
{
"key": "security",
"band": "at_risk",
"name": "Security",
"value": 39,
"weight": 0.16,
"metrics": [
{
"key": "security_posture",
"band": "at_risk",
"name": "Security posture",
"note": "Excluded from scoring (no data or not applicable): CI-Tests. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"ci_tests"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 39,
"inputs": {
"source": "openssf_scorecard",
"checks_evaluated": 17,
"scorecard_version": "v5.5.0",
"checks_inconclusive": 1,
"scorecard_aggregate": 3.9
},
"components": [
{
"key": "binary_artifacts",
"name": "Binary-Artifacts",
"detail": "no binaries found in the repo",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "branch_protection",
"name": "Branch-Protection",
"detail": "branch protection is not maximal on development and all release branches",
"points": 3.8,
"status": "partial",
"details": [],
"max_points": 7.5
},
{
"key": "ci_tests",
"name": "CI-Tests",
"detail": "internal error: internal error: Client.Repositories.ListStatuses: internal error: ListStatuses: GET https://api.github.com/repos/majorcontext/moat/commits/794e8429841f7301fa8cf3f8c748f8e14e35ace4/statuses: 504 We couldn't respond to your request in time. Sorry about that. Please try resubmitting your request and contact us if the problem persists. []",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 2.5
},
{
"key": "cii_best_practices",
"name": "CII-Best-Practices",
"detail": "no effort to earn an OpenSSF best practices badge detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 2.5
},
{
"key": "code_review",
"name": "Code-Review",
"detail": "Found 3/30 approved changesets -- score normalized to 1",
"points": 0.8,
"status": "partial",
"details": [],
"max_points": 7.5
},
{
"key": "contributors",
"name": "Contributors",
"detail": "project has 6 contributing companies or organizations",
"points": 2.5,
"status": "met",
"details": [],
"max_points": 2.5
},
{
"key": "dangerous_workflow",
"name": "Dangerous-Workflow",
"detail": "no dangerous workflow patterns detected",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "dependency_update_tool",
"name": "Dependency-Update-Tool",
"detail": "no update tool detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "fuzzing",
"name": "Fuzzing",
"detail": "project is not fuzzed",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "license",
"name": "License",
"detail": "license file detected",
"points": 2.5,
"status": "met",
"details": [],
"max_points": 2.5
},
{
"key": "maintained",
"name": "Maintained",
"detail": "30 commit(s) and 16 issue activity found in the last 90 days -- score normalized to 10",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "packaging",
"name": "Packaging",
"detail": "packaging workflow detected",
"points": 5,
"status": "met",
"details": [],
"max_points": 5
},
{
"key": "pinned_dependencies",
"name": "Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 1",
"points": 0.5,
"status": "partial",
"details": [],
"max_points": 5
},
{
"key": "sast",
"name": "SAST",
"detail": "SAST tool is not run on all commits -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "security_policy",
"name": "Security-Policy",
"detail": "security policy file not detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "signed_releases",
"name": "Signed-Releases",
"detail": "Project has not signed or included provenance with any releases.",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "token_permissions",
"name": "Token-Permissions",
"detail": "detected GitHub workflow tokens with excessive permissions",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "vulnerabilities",
"name": "Vulnerabilities",
"detail": "27 existing vulnerabilities detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
}
]
},
{
"key": "high_risk_jurisdiction_exposure",
"band": "excellent",
"name": "High-Risk Jurisdiction Exposure",
"note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
"notes": [
{
"code": "jurisdiction_evidence_limits",
"params": {}
}
],
"value": 100,
"inputs": {
"meaning": "self-published location evidence; not nationality or citizenship",
"red_flag": false,
"exposures": [],
"policy_countries": [
"Russia",
"Iran",
"North Korea"
],
"review_only_matches": 0,
"assessed_self_published_locations": 12
},
"components": [
{
"key": "policy_exposure_multiplier",
"name": "Policy exposure multiplier",
"detail": "no confirmed policy-scope location match",
"points": 100,
"status": "met",
"details": [
{
"code": "jurisdiction_no_match",
"params": {}
}
],
"max_points": 100
}
]
}
],
"description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
},
{
"key": "ai_readiness",
"band": "good",
"name": "AI Readiness",
"value": 80,
"weight": 0,
"metrics": [
{
"key": "ai_agent_context",
"band": "excellent",
"name": "Agent context & guidance",
"note": null,
"notes": [],
"value": 85,
"inputs": {
"has_llms_txt": false,
"legible_history_share": 1,
"agent_instruction_files": [
"CLAUDE.md"
],
"agent_instruction_max_bytes": 14031
},
"components": [
{
"key": "agent_instructions",
"name": "Agent instructions",
"detail": "CLAUDE.md",
"points": 45,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "CLAUDE.md"
}
}
],
"max_points": 45
},
{
"key": "machine_readable_docs_llms_txt",
"name": "Machine-readable docs (llms.txt)",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
},
{
"key": "legible_commit_history",
"name": "Legible commit history",
"detail": "100 of 100 human commits state their intent (structured subject or explanatory body)",
"points": 40,
"status": "met",
"details": [
{
"code": "legible_history",
"params": {
"legible": 100,
"sampled": 100
}
}
],
"max_points": 40
}
]
},
{
"key": "ai_verify_loop",
"band": "good",
"name": "Verify loop (build / test / typecheck)",
"note": null,
"notes": [],
"value": 83,
"inputs": {
"has_nix": false,
"has_tests": true,
"lockfiles": [
"go.sum"
],
"has_dockerfile": true,
"typed_language": true,
"bootstrap_files": [
"Makefile"
],
"has_devcontainer": false,
"has_linter_config": true,
"typecheck_configs": [],
"agent_commit_share": 0.25,
"toolchain_manifests": [
"examples/language-server/go.mod",
"go.mod"
],
"dependency_bot_commit_share": 0
},
"components": [
{
"key": "one_command_bootstrap",
"name": "One-command bootstrap",
"detail": "Makefile",
"points": 18,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "Makefile"
}
}
],
"max_points": 18
},
{
"key": "automated_tests",
"name": "Automated tests",
"detail": null,
"points": 22,
"status": "met",
"details": [],
"max_points": 22
},
{
"key": "lint_format_config",
"name": "Lint / format config",
"detail": ".golangci.yml",
"points": 11,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": ".golangci.yml"
}
}
],
"max_points": 11
},
{
"key": "static_type_checking",
"name": "Static type checking",
"detail": "Go (statically typed)",
"points": 11,
"status": "met",
"details": [
{
"code": "statically_typed_language",
"params": {
"language": "Go"
}
}
],
"max_points": 11
},
{
"key": "reproducible_environment",
"name": "Reproducible environment",
"detail": "Dockerfile, lockfile",
"points": 10,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "Dockerfile, lockfile"
}
}
],
"max_points": 10
},
{
"key": "demonstrated_agent_practice",
"name": "Demonstrated agent practice",
"detail": "25 of the last 100 commits agent-authored or agent-credited",
"points": 10,
"status": "met",
"details": [
{
"code": "agent_authored_commits",
"params": {
"count": 25,
"sampled": 100
}
}
],
"max_points": 10
},
{
"key": "automated_maintenance",
"name": "Automated maintenance",
"detail": "no automated dependency updates observed",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_dependency_automation",
"params": {}
}
],
"max_points": 8
},
{
"key": "openssf_scorecard_pinned_dependencies",
"name": "OpenSSF Scorecard: Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 1",
"points": 1,
"status": "partial",
"details": [],
"max_points": 10
}
]
},
{
"key": "ai_code_legibility",
"band": "excellent",
"name": "Code legibility for models",
"note": null,
"notes": [],
"value": 99,
"inputs": {
"primary_language": "Go",
"largest_source_bytes": 108328,
"source_files_sampled": 543,
"oversized_source_files": 6
},
"components": [
{
"key": "type_checkable_code",
"name": "Type-checkable code",
"detail": "Go (statically typed)",
"points": 45,
"status": "met",
"details": [
{
"code": "statically_typed_language",
"params": {
"language": "Go"
}
}
],
"max_points": 45
},
{
"key": "manageable_file_sizes",
"name": "Manageable file sizes",
"detail": "6/543 source files over 60KB",
"points": 54.4,
"status": "partial",
"details": [
{
"code": "oversized_source_files",
"params": {
"kb": 60,
"sampled": 543,
"oversized": 6
}
}
],
"max_points": 55
}
]
},
{
"key": "ai_interfaces",
"band": "at_risk",
"name": "Machine-readable interfaces",
"note": null,
"notes": [],
"value": 40,
"inputs": {
"example_dirs": [
"examples"
],
"has_mcp_signal": false,
"api_schema_files": []
},
"components": [
{
"key": "api_schema_openapi_graphql_proto",
"name": "API schema (OpenAPI/GraphQL/proto)",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 40
},
{
"key": "mcp_server",
"name": "MCP server",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 20
},
{
"key": "runnable_examples",
"name": "Runnable examples",
"detail": "examples",
"points": 40,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "examples"
}
}
],
"max_points": 40
}
]
}
],
"description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
}
],
"metrics_version": "1.13.0"
},
"warnings": [
"Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
"GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository"
],
"report_type": "repository",
"generated_at": "2026-07-26T01:54:49.243847Z",
"schema_version": "0.27.0",
"badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/m/majorcontext/moat.svg",
"full_name": "majorcontext/moat",
"license_state": "standard",
"license_spdx": "MIT"
}