{"id":49790761,"url":"https://github.com/itsuzef/goalkeeper","last_synced_at":"2026-05-17T09:01:21.681Z","repository":{"id":357032304,"uuid":"1235028451","full_name":"itsuzef/goalkeeper","owner":"itsuzef","description":"Durable contract-driven goal execution for Claude Code. A subagent judge gates completion against an explicit Definition of Done.","archived":false,"fork":false,"pushed_at":"2026-05-12T02:28:27.000Z","size":241,"stargazers_count":7,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-14T06:02:58.644Z","etag":null,"topics":["agents","ai-agents","anthropic","automation","autonomous-agents","claude-code","claude-code-plugin","goals"],"latest_commit_sha":null,"homepage":"https://dev.to/itsuzef/the-judge-gate-why-a-passing-validator-isnt-a-finished-feature-f2f","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/itsuzef.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-11T00:07:02.000Z","updated_at":"2026-05-12T17:32:49.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/itsuzef/goalkeeper","commit_stats":null,"previous_names":["itsuzef/goalkeeper"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/itsuzef/goalkeeper","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itsuzef%2Fgoalkeeper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itsuzef%2Fgoalkeeper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itsuzef%2Fgoalkeeper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itsuzef%2Fgoalkeeper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/itsuzef","download_url":"https://codeload.github.com/itsuzef/goalkeeper/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itsuzef%2Fgoalkeeper/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33095030,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-16T04:41:52.686Z","status":"ssl_error","status_checked_at":"2026-05-16T04:41:52.009Z","response_time":115,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agents","ai-agents","anthropic","automation","autonomous-agents","claude-code","claude-code-plugin","goals"],"created_at":"2026-05-12T04:01:34.874Z","updated_at":"2026-05-17T09:01:21.613Z","avatar_url":"https://github.com/itsuzef.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"branding/lockup.svg\" alt=\"goalkeeper\" width=\"360\"\u003e\n  \u003cbr\u003e\n  \u003ch3\u003eSet durable goals. Approve at the gate.\u003c/h3\u003e\n  \u003cp\u003eContract-driven autonomous goal execution for \u003ca href=\"https://docs.claude.com/en/docs/claude-code/overview\"\u003eClaude Code\u003c/a\u003e.\u003cbr\u003eA subagent judge gates completion against an explicit Definition of Done.\u003c/p\u003e\n  \u003cp\u003e\n    \u003ca href=\"https://github.com/itsuzef/goalkeeper/actions/workflows/test.yml\"\u003e\u003cimg alt=\"test\" src=\"https://github.com/itsuzef/goalkeeper/actions/workflows/test.yml/badge.svg\"\u003e\u003c/a\u003e\n    \u003cimg alt=\"license\" src=\"https://img.shields.io/badge/license-MIT-0E7C66\"\u003e\n    \u003cimg alt=\"version\" src=\"https://img.shields.io/badge/version-0.1.11-0E7C66\"\u003e\n    \u003cimg alt=\"claude-code\" src=\"https://img.shields.io/badge/claude--code-plugin-0E7C66\"\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\n\u003c!--\nDEMO SLOT — when you record an asciinema cast, replace this comment with:\n\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://asciinema.org/a/XXXXXX\"\u003e\n    \u003cimg src=\"https://asciinema.org/a/XXXXXX.svg\" alt=\"goalkeeper reject-then-approve demo\" width=\"720\"\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\nSwap XXXXXX for the cast ID returned by `asciinema upload demo.cast`.\nUntil then, the example below is the canonical \"real reject-cycle\" reference.\n--\u003e\n\n\u003e **Real reject-cycle, 3 minutes wall-clock.** Goalkeeper caught a `MAX_RUNTIME_MS = 9999 // TODO` sentinel placeholder in a benchmark test where the validator passed both rounds. Round 1: validator green, judge **reject** on DoD #3 + #7 with a 3-step fix-list. Round 2: real threshold (500ms = 10x measured baseline) with justification, validator green, judge **approve**. Full transcript with quoted verdicts: [`docs/demo.md`](./docs/demo.md). Long-form writeup on [dev.to](https://dev.to/itsuzef/the-judge-gate-why-a-passing-validator-isnt-a-finished-feature-f2f).\n\n---\n\n## How it differs\n\n|  | OpenAI Codex `/goal` | Ralph loop | **goalkeeper** |\n|---|---|---|---|\n| Durable goal across many turns | ✓ | ✓ | ✓ |\n| Validator back-pressure | optional | core | core |\n| **Independent judge gate against an explicit Definition of Done** | — | — | **core** |\n| Anti-placeholder rule (stubs / `.todo` / `it.only` auto-reject) | — | informal | **enforced** |\n| Linear chains of role-specific goals with judge-gated handoff | — | — | **`/goal-chain`** |\n| Auto-pauses after N consecutive rejections | — | — | **5 (configurable)** |\n| Append-only checkpoint log per goal | — | informal | enforced |\n| Spec lives in | CLI prompt | `PROMPT.md` | `contract.md` (validated against JSON Schema) |\n| Pre-existing validator failures distinguished from goal-caused | — | — | **`validator_baseline_*`** |\n\nInspired by [OpenAI Codex `/goal`](https://developers.openai.com/codex/use-cases/follow-goals) and Geoffrey Huntley's [Ralph loop](https://ghuntley.com/ralph/), with one key addition: the judge.\n\n## Why\n\nCodex `/goal` runs autonomously until a stop-condition is met. The Ralph loop runs `while :; do cat PROMPT.md | claude-code; done` and leans on validators (compile, test, lint) to back-pressure the model. Both work, but both have the same failure mode: **a passing validator is not the same as a finished feature**. Tests can pass on stubs. Linters can pass on `.todo`s. Codex can declare victory the moment its stop-condition string matches.\n\ngoalkeeper adds a second gate. After your validator passes, a fresh subagent — independent context, no rationalizations from the executing agent — reviews the diff and the progress log against your written Definition of Done, and either approves or returns a structured fix-list. After 5 rejections it pauses and asks for human help.\n\n## Install\n\nAdd the goalkeeper marketplace, then install the plugin:\n\n```bash\n# inside Claude Code\n/plugin marketplace add itsuzef/goalkeeper\n/plugin install goalkeeper@goalkeeper\n```\n\nSkills become available under the `goalkeeper:` namespace. Invoke as `/goalkeeper:goal \"\u003cobjective\u003e\"`, `/goalkeeper:goal-prep`, `/goalkeeper:goal-judge`, etc. (Most users alias the namespace away — see \"Aliasing\" below.)\n\n### Aliasing the namespace\n\nIf you primarily use goalkeeper and want shorter commands, add aliases to `~/.claude/settings.json`:\n\n```json\n{\n  \"aliases\": {\n    \"/goal\": \"/goalkeeper:goal\",\n    \"/goal-prep\": \"/goalkeeper:goal-prep\",\n    \"/goal-pause\": \"/goalkeeper:goal-pause\",\n    \"/goal-resume\": \"/goalkeeper:goal-resume\",\n    \"/goal-clear\": \"/goalkeeper:goal-clear\",\n    \"/goal-judge\": \"/goalkeeper:goal-judge\",\n    \"/goal-chain\": \"/goalkeeper:goal-chain\"\n  }\n}\n```\n\n## Quick start\n\n```\n/goal-prep \"Migrate the test suite from Jest to Vitest\"\n```\n\ngoalkeeper reads your repo, asks a few targeted questions (objective, definition-of-done, validator command, non-goals), writes `.claude/goals/\u003cslug\u003e/contract.md`, and offers to start. Once running, it:\n\n1. Works in checkpoints (logged to `log.md`).\n2. Runs your validator after each checkpoint.\n3. When the validator passes, spawns a subagent **judge** to check Definition of Done.\n4. Judge approves → done. Judge rejects → fix-list logged, work continues. After 5 rejections → paused for you.\n\nCheck status anytime:\n\n```\n/goal\n```\n\n## Commands\n\n| Command | What it does |\n|---|---|\n| `/goal \"\u003cobjective\u003e\"` | Start (or resume) a goal. Auto-routes to `/goal-prep` if no contract exists yet. |\n| `/goal` | Show status of the active goal: last checkpoint, validator state, rejection count. |\n| `/goal-prep \"\u003crough idea\u003e\"` | Interactively draft a contract — the highest-leverage step. Surveys the repo and uses targeted questions to lock in a precise spec. |\n| `/goal-pause` | Pause without losing state. Pending wakeups become no-ops. |\n| `/goal-resume` | Resume a paused goal. If resuming from `needs_human`, asks whether to reset the rejection counter. |\n| `/goal-clear` | Stop and archive the goal to `.claude/goals/_archive/`. Files are moved, never deleted. |\n| `/goal-judge` | Run the judge advisorily on the active goal (no state change). Useful as a manual sanity check. |\n| `/goal-chain \"\u003cfile\u003e\"` | Run a linear sequence of goals; the judge gates progression between them. |\n\n## Contract format\n\nA contract is a markdown file at `.claude/goals/\u003cslug\u003e/contract.md` with frontmatter:\n\n```yaml\n---\nslug: jest-to-vitest-migration\nobjective: Migrate the test suite from Jest to Vitest with no behavioral regressions and a measurable speed improvement.\nnon_goals:\n  - Do not rewrite test logic\n  - Do not change source code under src/\ndefinition_of_done:\n  - All test files import from \"vitest\" instead of \"@jest/globals\"\n  - jest.config.* is removed; vitest.config.ts exists with equivalent coverage thresholds\n  - \"pnpm test\" runs the full suite under Vitest with 100% of previously-passing tests still passing\n  - Wall-clock test runtime improves by at least 20% vs the Jest baseline\nvalidator:\n  command: pnpm test --run \u0026\u0026 pnpm exec node scripts/check-no-jest-refs.mjs\n  success: exit_zero\n  timeout_seconds: 1200\ncheckpoint_cadence: every 5 file edits OR every 20 minutes\nmax_rejections: 5\njudge_mode: subagent\nwakeup_seconds: 270\n---\n\n## Context\n\u003cfreeform body — file pointers, constraints, hints, anti-placeholder reminders\u003e\n```\n\nThe body of the contract is your \"PROMPT.md\" — file pointers, constraints, hints. See [`examples/`](./examples/) for full contracts.\n\nSchema: [`schemas/contract.schema.json`](./schemas/contract.schema.json).\n\n### Field reference\n\n- **slug** — kebab-case directory name. Must be unique within `.claude/goals/`.\n- **objective** — one sentence, what success looks like.\n- **non_goals** — explicit out-of-scope items. Judge rejects on violation even if DoD is met.\n- **definition_of_done** — what the judge grades against. Be specific; \"works correctly\" is not a DoD.\n- **validator.command** — runs after each checkpoint. Necessary but not sufficient.\n- **validator.success** — `exit_zero` (default) or `regex:\u003cpattern\u003e` matched against stdout.\n- **checkpoint_cadence** — agent's guidance for how often to log + validate.\n- **max_rejections** — default 5. After this many judge rejections, pauses for human.\n- **judge_mode** — `subagent` (default, gate-quality) or `inline` (cheap, advisory only).\n- **wakeup_seconds** — between-iteration delay. Tune to validator runtime; goalkeeper picks cache-aware default if unset.\n- **diff_excludes** — additional pathspec globs the judge should ignore. Appended to defaults (lockfiles, `dist/`, `build/`, `coverage/`, IDE files). Add per-repo noise like generated migrations or vendor trees.\n\n## Chains\n\nA chain is an ordered list of slugs. The judge gates progression — only after approval does the next goal start.\n\n```markdown\n---\nname: bonfire-bass-rust-port\n---\n\n1. port-dsp-core-to-rust\n2. wire-up-ffi-shim\n3. swap-cpp-for-rust-in-host\n4. delete-cpp-tree\n```\n\nRun with:\n\n```\n/goal-chain \".claude/goals/chains/bonfire-bass.md\"\n```\n\nEach slug must already have a contract at `.claude/goals/\u003cslug\u003e/contract.md`. Run `/goal-prep` for each before starting the chain.\n\n## Multi-role goals\n\nMost non-trivial goals span multiple roles — backend changes, UI wiring, migrations, tests, docs. Goalkeeper deliberately keeps just two agent slots (executor + judge) and stays framework-agnostic about how you spawn specialists. There are two patterns for getting role-shaped work through goalkeeper, and the right choice depends on how decoupled the roles are.\n\n### Pattern A — chain of role-specific contracts (default)\n\nFrame each role as its own contract with its own Definition of Done, validator, and judge. Compose them with `/goal-chain`. The judge gates progression: backend's judge has to approve before UI starts; UI's judge has to approve before migrations.\n\n```markdown\n---\nname: stripe-integration\n---\n\n1. stripe-api-routes\n2. stripe-db-migration\n3. stripe-checkout-ui\n4. stripe-e2e-tests\n```\n\nEach slug has its own `.claude/goals/\u003cslug\u003e/contract.md` with a focused DoD (\"Stripe webhook signature verification works\", \"checkout component handles 3DS challenge\", etc.) and a focused validator (`pnpm test packages/api`, `pnpm test packages/web`, etc.). See [`examples/chain.md`](./examples/chain.md) for a worked example.\n\n**Choose Pattern A when:** roles are sequenceable. One role's work produces the artifacts the next role consumes. The dependency graph is linear or close to it. You want the judge to gate-keep at each role boundary so a sloppy backend can't silently corrupt the UI step.\n\n**Tradeoff:** chains force upfront decomposition. You have to know the boundaries before you start. If the boundaries shift mid-flight, you have to clear the chain and re-plan.\n\n### Pattern B — in-goal `specialists:` orchestration (proposed for v0.2)\n\nFor tightly-coupled cross-role work — same files, can't be sequenced — Pattern A creates artificial mid-flight pauses. Pattern B is the escape hatch: a single contract with a `specialists:` field that lists the roles available, plus role-specific system prompts. The executing agent is the orchestrator and dispatches subtasks to specialist subagents (Claude Code general-purpose agents with custom system prompts, your own `subagent_type` definitions, or MCP-based agents — goalkeeper doesn't ship specialist definitions).\n\n```yaml\nspecialists:\n  - role: backend\n    system_prompt: \"You are a senior Node.js engineer. ...\"\n  - role: ui\n    system_prompt: \"You are a senior React engineer. ...\"\n```\n\nThe judge still gates final approval against the unified DoD; the executing agent's log records which specialist did what.\n\n**Status: proposed for v0.2 — not yet implemented.** The `specialists:` field is not in `schemas/contract.schema.json` yet. If you need this today, write your own orchestration in the body of the contract and have the executing agent spawn subagents using whatever Claude Code mechanism you prefer; goalkeeper observes via the log and the judge gates the result against the unified DoD.\n\n**Choose Pattern B when:** specialists genuinely have to interleave on the same files. A frontend change requires a simultaneous backend change, both committed together, both tested together. Pattern A would create a contract that artificially pauses the work mid-flight.\n\n**Tradeoff:** the executing agent owns coordination state, and the judge has to reason about multiple specialists' contributions in a single DoD pass. Easier bugs to hide than in chains.\n\n### Default: prefer A unless you can articulate why A doesn't fit\n\nIf you can list the roles in dependency order and each role can complete independently before the next starts, use Pattern A. Reach for Pattern B only when the roles must touch the same code in the same edit.\n\n## Missions — supervised iterative arcs (v0.2)\n\nFor multi-goal work where each next goal's shape is informed by the prior goal's actual output, the supervisor primitive sits one level above goals. Where the judge gates a *goal* against its Definition of Done, the supervisor gates the *mission* against its charter and adaptively decides what goal to run next.\n\nAuthoring a mission charter at `.claude/mission.md`:\n\n```markdown\n# Mission: v2-cutover\n\n## Objective\nShip V2 cold-inbound to production safely.\n\n## Success condition\nAll 6 cutover gates pass on a 2-week shadow window + 5%→25%→100% canary clean.\n\n## Constraints\n- Never send V2 outbound during shadow.\n- Any cutover gate fail → fix + restart shadow.\n- Max 2 weeks elapsed before user checkpoint.\n\n## Legal next-goal shapes\n- shadow-infra — assemble pipeline + tee + writer\n- gate-fix — patch a specific failing axis from shadow data\n- canary-rollout — % hash routing\n- rollback — revert canary % to 0\n\n## Done is not\n- Just \"validator passes.\" Done is \"6 gates pass on shadow + canary green at 100%.\"\n```\n\nAfter a goal completes, `/goalkeeper:goal-supervisor` reads the charter + the prior goal's artifacts and decides:\n\n- **PROCEED** — drafts the next goal's objective (informed by what the prior goal actually produced) and hands off to `/goalkeeper:goal-prep` for user-reviewable contract drafting.\n- **DONE** — mission's success condition is satisfied; writes `.claude/mission-completed.md` with evidence per success-condition item.\n- **ESCALATE** — supervisor can't decide; surfaces the ambiguity to the user with concrete required input.\n\nMissions are NOT chains. Chains commit to a pre-determined linear sequence; missions adaptively decide the next goal based on prior outputs. Pick the right primitive: chains for sequenceable work known up front, missions for arcs where the shape of step N+1 depends on what step N actually produced.\n\n## State and storage\n\n```\n.claude/\n  mission.md                     # user-authored charter (v0.2, opt-in)\n  mission.json                   # supervisor state\n  mission-log.md                 # append-only mission-level audit trail\n  mission-completed.md           # final snapshot on supervisor DONE\n  goals/\n    active.json                  # pointer to current slug (or terminal record)\n    chain.json                   # current chain, if any\n    .gitignore                   # ignores all goal dirs except shared/ (opt-in)\n    \u003cslug\u003e/\n      contract.md                # the spec\n      state.json                 # status, rejection_count, git baseline, validator/judge results\n      log.md                     # append-only checkpoint + verdict log\n    _archive/                    # cleared goals (moved, never deleted)\n    shared/                      # opt-in committed contracts for team sharing\n```\n\nBy default everything under `.claude/goals/` is gitignored. To share a contract with your team, place it under `.claude/goals/shared/\u003cslug\u003e/contract.md`. The mission files (`mission.md`/`mission.json`/`mission-log.md`) live at `.claude/` root and are NOT auto-gitignored — author your mission charter the way you want it tracked.\n\n### Canonical state shapes\n\nThe skills (`goal`, `goal-clear`, `goal-judge`, `goal-chain`) all read and write the same shapes. Single source of truth lives in [`skills/goal/SKILL.md`](./skills/goal/SKILL.md) under \"Canonical state shapes\"; the reference here is for users.\n\n**`active.json`** — exactly two shapes, active or terminal:\n\n```json\n// Active\n{\"slug\": \"\u003cslug\u003e\", \"activated_at\": \"\u003cISO\u003e\", \"chain\": \"\u003cchain\u003e\"}  // chain is optional\n\n// Terminal\n{\n  \"slug\": null,\n  \"ended_at\": \"\u003cISO\u003e\",\n  \"ended_reason\": \"done\" | \"cleared\" | \"chain_completed\" | \"aborted\",\n  \"previous_slug\": \"\u003cslug\u003e\",\n  \"previous_chain\": \"\u003cchain\u003e\"\n}\n```\n\n**`\u003cslug\u003e/state.json`** — required fields on activation: `status`, `rejection_count`, `started_at`, `started_at_commit`, `started_at_dirty_paths`. Optional baseline-capture fields: `validator_baseline_result` (pass/fail/not_runnable/null) and `validator_baseline_failing_paths` (paths the validator was already failing on at activation — the judge subtracts these so pre-existing debt doesn't block goal approval). Populated as the goal runs: `chain_step`, `last_checkpoint_at`, `last_validator_result`, `last_judge_verdict`, `approved_at`, `paused_at`, `resumed_at`, `needs_human_at`.\n\n**`chain.json`** — `name`, `slugs[]`, `cursor`, `status`, `started_at`, `completed_at`, `source_file`, `link_approvals[]`. The `link_approvals` array accumulates `{slug, approved_at}` entries as each link is judge-approved, providing chain-level visibility independent of per-link state files.\n\n## Design notes\n\n- **The contract is the spec.** Bad contracts produce bad work. `/goal-prep` is mandatory because thin contracts are goalkeeper's #1 failure mode.\n- **Judge ≠ validator.** Validators check that things work; the judge checks that the *right* things work. Validator passing is necessary but not sufficient.\n- **Subagent judge is the gate.** Independent context catches the placeholders and shortcuts the executing agent rationalized away. Inline judge mode exists for cheap advisory review only — do not use it as a gate.\n- **Append-only log.** Logs are forensic artifacts. Past entries are never deleted or rewritten.\n- **Cache-aware wakeup delays.** Anthropic's prompt cache has a 5-minute TTL. goalkeeper picks delays that either stay warm (60–270s) or commit to long waits (1200s+) — never the worst-of-both 300s.\n- **Anti-placeholder.** Borrowed verbatim from Ralph: stubs, mocks, `.todo`, `.skip`, and \"TODO: real implementation\" are automatic judge rejection.\n\n## Prior art\n\n- **OpenAI Codex `/goal`** — the durable-objective + stop-condition pattern. goalkeeper mirrors the lifecycle (set, status, pause, resume, clear) and adds prep, judge, and chain. ([docs](https://developers.openai.com/codex/use-cases/follow-goals))\n- **Ralph (Geoffrey Huntley)** — the embedded-validator loop. goalkeeper adopts the validator philosophy and the anti-placeholder rule, and adds an external judge. ([blog post](https://ghuntley.com/ralph/))\n\n## License\n\nMIT — see [LICENSE](./LICENSE).\n\n## Brand\n\nBrand assets (logo, wordmark, social card) live in [`branding/`](./branding/) — see the [brand README](./branding/README.md) for usage notes, color palette, and SVG→PNG conversion. Drafts and alternates are intentionally outside this repo.\n\n---\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"branding/mark.svg\" alt=\"goalkeeper\" width=\"48\"\u003e\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fitsuzef%2Fgoalkeeper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fitsuzef%2Fgoalkeeper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fitsuzef%2Fgoalkeeper/lists"}