feat: project-webhook — HTTP endpoint to trigger new-project from claude.ai #10

Closed
opened 2026-05-14 13:56:23 +00:00 by mathias · 1 comment
Owner

Problem

hyperguild new-project will be a CLI command — callable from a terminal or Claude Code session. But from claude.ai web/mobile, there is no way to trigger it directly because:

  • GitHub remote MCP requires OAuth not supported in claude.ai
  • Claude Code is not running during a claude.ai chat session
  • The only available channels from claude.ai are: connected MCP servers (Gitea, brain, Google) and HTTP endpoints reachable via those connectors

Solution

Add a lightweight webhook endpoint to the existing cmd/routing HTTP server (which already runs on koala as an MCP server behind Dex/OAuth). A single new route:

POST /webhook/new-project
Authorization: Bearer <token>
Content-Type: application/json

{
  "name":        "my-experiment",
  "description": "One-line description for GitHub repo and experiment brief",
  "hypothesis":  "We believe X will produce Y, measurable by Z",
  "folder":      "AGENTS",
  "stack":       "go-agent",
  "private":     true
}

Response:

{
  "github_url":    "https://github.com/mathiasb/my-experiment",
  "gitea_url":     "http://gitea.d-ma.be/mathias/my-experiment",
  "issue_url":     "https://github.com/mathiasb/my-experiment/issues/1",
  "next_steps":    "cd ~/dev/AGENTS/my-experiment && task new-project -- my-experiment personal AGENTS go-agent && git remote add origin https://github.com/mathiasb/my-experiment.git && git push -u origin main"
}

How claude.ai calls it

The routing pod is already exposed as an MCP server via gitea-mcp-adjacent infrastructure. Two options:

Option A: Add project_create as a new MCP tool in the routing pod's tool registry — callable directly from claude.ai via the existing connector.

Option B: Expose as a plain HTTP endpoint, call it from claude.ai via a new minimal MCP tool hyperguild_webhook that wraps the HTTP call.

Recommendation: Option A — the routing pod already has the MCP server infrastructure (mcp.NewServer, registry.New()), auth via Dex JWT, and is reachable from claude.ai. Adding a tool is a single reg.Register(...) call.

What the tool does (v1, three steps)

  1. Create GitHub repo from template (template-go-agent or template-go-web)

    • GitHub API: POST /repos/mathiasb/template-go-agent/generate
    • Requires: GitHub PAT with repo scope in env/secret
  2. Commit staging namespace manifest to infra repo

    • Via gitea-mcp internal client: new file at k8s/staging/<name>/namespace.yaml
    • Triggers Flux reconciliation on koala → staging env comes up automatically
  3. Open GitHub issue with experiment brief

    • GitHub API: POST /repos/mathiasb/<name>/issues
    • Body: hypothesis + success criterion from request payload

Returns URLs + next_steps string with exact local commands to run.

What it does NOT do (v2+)

  • Clone locally (local-dev's job: task new-project)
  • Set up agent-policy.yaml (v2)
  • Configure ntfy approval routing (v2)
  • Start Claude Code session (always human decision)

Security

  • Auth: existing Dex JWT validation already in cmd/routing/main.go
  • The endpoint is CRITICAL risk — creates GitHub repos and infra manifests
  • ntfy approval required before execution (use existing approval middleware pattern)
  • Idempotent: if repo already exists on GitHub, return existing URLs without error

Required secrets/config (new)

GITHUB_PAT=ghp_...          # repo scope: create repos, open issues
GITHUB_OWNER=mathiasb       # GitHub username
INFRA_REPO=mathias/infra    # Gitea repo to commit namespace manifest to

Testing the concept (before full implementation)

Minimal proof-of-concept to validate the claude.ai → webhook → koala flow:

  1. Add a ping_project MCP tool to routing pod that takes {name: string} and returns {echo: name, timestamp: ...}
  2. Connect to it from claude.ai via the existing routing pod connector
  3. Verify the round-trip works end-to-end

If ping works → full implementation is straightforward.

  • hyperguild-new-project-bootstrap (brain)
  • gitea-mcp #13 repo_create
  • gitea-mcp #16 repo_mirror_push
  • local-dev #6 print git remote add command
## Problem `hyperguild new-project` will be a CLI command — callable from a terminal or Claude Code session. But from **claude.ai web/mobile**, there is no way to trigger it directly because: - GitHub remote MCP requires OAuth not supported in claude.ai - Claude Code is not running during a claude.ai chat session - The only available channels from claude.ai are: connected MCP servers (Gitea, brain, Google) and HTTP endpoints reachable via those connectors ## Solution Add a lightweight webhook endpoint to the existing `cmd/routing` HTTP server (which already runs on koala as an MCP server behind Dex/OAuth). A single new route: ``` POST /webhook/new-project Authorization: Bearer <token> Content-Type: application/json { "name": "my-experiment", "description": "One-line description for GitHub repo and experiment brief", "hypothesis": "We believe X will produce Y, measurable by Z", "folder": "AGENTS", "stack": "go-agent", "private": true } ``` Response: ```json { "github_url": "https://github.com/mathiasb/my-experiment", "gitea_url": "http://gitea.d-ma.be/mathias/my-experiment", "issue_url": "https://github.com/mathiasb/my-experiment/issues/1", "next_steps": "cd ~/dev/AGENTS/my-experiment && task new-project -- my-experiment personal AGENTS go-agent && git remote add origin https://github.com/mathiasb/my-experiment.git && git push -u origin main" } ``` ## How claude.ai calls it The routing pod is already exposed as an MCP server via gitea-mcp-adjacent infrastructure. Two options: **Option A:** Add `project_create` as a new MCP tool in the routing pod's tool registry — callable directly from claude.ai via the existing connector. **Option B:** Expose as a plain HTTP endpoint, call it from claude.ai via a new minimal MCP tool `hyperguild_webhook` that wraps the HTTP call. **Recommendation: Option A** — the routing pod already has the MCP server infrastructure (`mcp.NewServer`, `registry.New()`), auth via Dex JWT, and is reachable from claude.ai. Adding a tool is a single `reg.Register(...)` call. ## What the tool does (v1, three steps) 1. **Create GitHub repo** from template (`template-go-agent` or `template-go-web`) - GitHub API: `POST /repos/mathiasb/template-go-agent/generate` - Requires: GitHub PAT with `repo` scope in env/secret 2. **Commit staging namespace manifest** to infra repo - Via gitea-mcp internal client: new file at `k8s/staging/<name>/namespace.yaml` - Triggers Flux reconciliation on koala → staging env comes up automatically 3. **Open GitHub issue** with experiment brief - GitHub API: `POST /repos/mathiasb/<name>/issues` - Body: hypothesis + success criterion from request payload Returns URLs + `next_steps` string with exact local commands to run. ## What it does NOT do (v2+) - Clone locally (local-dev's job: `task new-project`) - Set up agent-policy.yaml (v2) - Configure ntfy approval routing (v2) - Start Claude Code session (always human decision) ## Security - Auth: existing Dex JWT validation already in `cmd/routing/main.go` - The endpoint is CRITICAL risk — creates GitHub repos and infra manifests - ntfy approval required before execution (use existing approval middleware pattern) - Idempotent: if repo already exists on GitHub, return existing URLs without error ## Required secrets/config (new) ``` GITHUB_PAT=ghp_... # repo scope: create repos, open issues GITHUB_OWNER=mathiasb # GitHub username INFRA_REPO=mathias/infra # Gitea repo to commit namespace manifest to ``` ## Testing the concept (before full implementation) Minimal proof-of-concept to validate the claude.ai → webhook → koala flow: 1. Add a `ping_project` MCP tool to routing pod that takes `{name: string}` and returns `{echo: name, timestamp: ...}` 2. Connect to it from claude.ai via the existing routing pod connector 3. Verify the round-trip works end-to-end If ping works → full implementation is straightforward. ## Related issues - hyperguild-new-project-bootstrap (brain) - gitea-mcp #13 repo_create - gitea-mcp #16 repo_mirror_push - local-dev #6 print git remote add command
Author
Owner

Architecture update — 2026-05-14

Original issue assumed we needed a separate webhook endpoint + GitHub API access from claude.ai. That's not needed.

Revised approach: Gitea-first, GitHub via push mirror

The complete new-project flow works entirely through the existing gitea-mcp connector already available in claude.ai:

claude.ai
  → gitea-mcp: repo_create (#13)         → Gitea repo created
  → gitea-mcp: repo_mirror_push (#16)    → Gitea push mirror to GitHub configured
                                              → GitHub repo appears automatically
  → gitea-mcp: file_write_branch         → staging namespace manifest committed to infra
                                              → Flux reconciles → staging env on koala
  → gitea-mcp: issue_create              → experiment brief as Gitea issue
                                              → mirrored to GitHub via push mirror

No new HTTP endpoints needed. No GitHub API access from claude.ai. No routing pod changes needed.

ADR exception (pragmatic)

GitHub-as-master ADR is preserved for all ongoing work (Claude Code, Actions, PRs). One exception: repo creation originates in Gitea, GitHub receives it via push mirror seconds later. After that, GitHub is canonical for all development.

What this issue becomes

Rather than a webhook endpoint, this is now about orchestrating the gitea-mcp tool sequence as a single composite project_create MCP tool in the routing pod's registry — callable directly from claude.ai as one action instead of four manual tool calls.

The composite tool: repo_create → repo_mirror_push → file_write_branch (infra) → issue_create, with idempotency and rollback on failure.

Blockers

  • gitea-mcp #13 repo_create
  • gitea-mcp #16 repo_mirror_push
  • gitea-mcp #12 repo_update (template flag, topics)

Test plan (manual, before composite tool)

  1. Run each gitea-mcp tool in sequence from claude.ai chat manually
  2. Verify GitHub repo appears via push mirror within 60s
  3. Verify Flux picks up staging namespace manifest
  4. Only then implement as composite MCP tool
## Architecture update — 2026-05-14 Original issue assumed we needed a separate webhook endpoint + GitHub API access from claude.ai. That's not needed. ## Revised approach: Gitea-first, GitHub via push mirror The complete `new-project` flow works entirely through the **existing gitea-mcp connector** already available in claude.ai: ``` claude.ai → gitea-mcp: repo_create (#13) → Gitea repo created → gitea-mcp: repo_mirror_push (#16) → Gitea push mirror to GitHub configured → GitHub repo appears automatically → gitea-mcp: file_write_branch → staging namespace manifest committed to infra → Flux reconciles → staging env on koala → gitea-mcp: issue_create → experiment brief as Gitea issue → mirrored to GitHub via push mirror ``` No new HTTP endpoints needed. No GitHub API access from claude.ai. No routing pod changes needed. ## ADR exception (pragmatic) GitHub-as-master ADR is preserved for all ongoing work (Claude Code, Actions, PRs). One exception: **repo creation originates in Gitea**, GitHub receives it via push mirror seconds later. After that, GitHub is canonical for all development. ## What this issue becomes Rather than a webhook endpoint, this is now about **orchestrating the gitea-mcp tool sequence as a single composite `project_create` MCP tool** in the routing pod's registry — callable directly from claude.ai as one action instead of four manual tool calls. The composite tool: repo_create → repo_mirror_push → file_write_branch (infra) → issue_create, with idempotency and rollback on failure. ## Blockers - gitea-mcp #13 repo_create - gitea-mcp #16 repo_mirror_push - gitea-mcp #12 repo_update (template flag, topics) ## Test plan (manual, before composite tool) 1. Run each gitea-mcp tool in sequence from claude.ai chat manually 2. Verify GitHub repo appears via push mirror within 60s 3. Verify Flux picks up staging namespace manifest 4. Only then implement as composite MCP tool
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mathias/hyperguild#10