Multi-module Go workspace with three modules:
forge-core/— Core library (registry, tools, security, channels, LLM)forge-cli/— CLI commands, TUI wizard, runtimeforge-plugins/— Channel plugins (telegram, slack), markdown converter
- Tenancy headers: every forge→platform HTTP callout (admission, remote session store, MCP platform token resolver) MUST send
Org-Id+Workspace-IdfromFORGE_ORG_ID/FORGE_WORKSPACE_IDenv alongsideAuthorization: Bearer ${FORGE_PLATFORM_TOKEN}— the platform verifies a PER-ORG HS256 token and needs Org-Id to pick the signing secret BEFORE it can validate the bearer (omitting it → 401 "missing org-id header"). Pattern lives inadmission_loader.go/remote_session_store.go/mcp/platform_token.go. - MCP auth types (
auth.type):oauth/bearer/static+ managedplatform(agent-principal token fromForgeConfig.Platform.token_endpoint) anduser(delegated, lazy — cannot berequired:true). The platform owns the op→identity split; forge only reads per-server config. - DEFER approval is FULLY BUILT & enforced (
forge-core/security/deferpolicy/, Slack Block-Kit delivery inforge-plugins/channels/slack/approvals.go):security.defer.tools.<toolName>{to: channel:slack:#x, approvers, timeout}— keyed by the RUNTIME tool name, which for MCP is<server>__<op>. GuardrailsapprovalGatesare parsed but NOT enforced — usesecurity.defer.*. - MCP OAuth discovery/DCR (
forge-core/mcp/oauth_discovery.go, #316/#320): RFC 9728→8414→7591.wellKnown()must INSERT the well-known segment for path-qualified issuers (Atlassianauth.atlassian.com/<id>) — replacing the path resolves the wrong AS.
Always run before committing:
# Format all modules
gofmt -w forge-core/ forge-cli/ forge-plugins/
# Lint all modules
golangci-lint run ./forge-core/...
golangci-lint run ./forge-cli/...
golangci-lint run ./forge-plugins/...Fix any lint errors and formatting issues before creating commits.
Run tests for affected modules before committing:
cd forge-core && go test ./...
cd forge-cli && go test ./...
cd forge-plugins && go test ./...