1 Contract Forge Adapter
jbr870 edited this page 2026-04-30 09:39:28 +00:00
Status Last updated Parent Read before this
complete 2026-04-30
Design - Architecture Overview
Design - Architecture Overview

Forge Adapter

The interface that lets devwork-skills run on any git forge — Forgejo, GitLab, GitHub, or no remote forge at all — without main skills branching on platform.

Current state

The contract is a specification document at _shared/forge-contract.md. It defines the operations main skills may call, their inputs and outputs, and their semantics. It is not executable code. It is the neutral surface both sides agree to: main skills read it to know what they may call; adapter skills read it to know what they must implement.

Adapters live as ordinary skills under .claude/skills/: /tea-cli for Forgejo, /glab-cli for GitLab, /gh-cli for GitHub, /local-fs for projects with no remote forge. Each adapter implements the operations defined in the contract using its platform's primitives, and declares its capability manifest in its own SKILL.md. The adapter is the source of truth for what it supports.

The active adapter for a project is declared in CLAUDE.md:

forge:
  adapter: tea-cli
  instance: git.wihslon.com
  owner: jbr870
  repo: medqair-api

When a main skill needs a forge operation, it reads this block and delegates to the named adapter. Switching forges is a single config change. Globally installed adapters can exceed what any single project uses; CLAUDE.md picks the active one.

Operation categories

The contract defines abstract operations grouped by purpose: issues (create_issue, add_comment, set_status, link_issues), wiki (read_wiki_page, write_wiki_page, list_wiki_pages), and the system-specific operations like post_phase_outcome (which is the structured handoff between skills, not a generic comment — see Contract - Phase Outcome).

The contract grows when the SDLC actually needs a new operation, not speculatively. New forge features don't drive contract growth — SDLC requirements do. When a main skill needs something new, the operation is added to the contract first, then implemented in each adapter that's actively used.

Capability handling

Forges have genuinely different capability surfaces. The architecture handles this without forcing the lowest common denominator:

  • Required capabilities are operations the SDLC genuinely needs. Every adapter must implement these.
  • Polyfills are capabilities the contract requires but a given forge doesn't natively support, implemented via available primitives. Example: label-based pseudo-projects on Forgejo where GitLab uses native Project boards.
  • Enrichments are capabilities a forge offers beyond the contract (GitLab Premium features, GitHub Actions). Adapters can take advantage internally; main skills don't depend on them.
  • Declared limitations are capabilities an adapter genuinely cannot provide. Surfaced in the adapter's capability manifest so main skills can fall back gracefully or fail clearly rather than crash.

Wiki rendering

Wiki data models differ enough to warrant explicit handling. Forgejo wikis are flat with a _Sidebar for navigation; GitLab and GitHub wikis support nested folders. The contract speaks in logical taxonomy (page name + section), not folder paths. Each adapter renders the taxonomy into its native structure:

  • GitLab/GitHub adapters: nested folders matching the taxonomy.
  • Forgejo adapter: flat pages with name conventions, _Sidebar regenerated to express structure.

This forces the documentation agent to think in taxonomy terms (which matches the Design - Wiki Layer anyway) and keeps the rendering decision local to each adapter.

The local-fs adapter

Projects without a remote forge — or that explicitly want to keep work local — use the local-fs adapter. It satisfies the same contract using the filesystem: "issues" are folders and files, "comments" append to those files, "status" is frontmatter, "wiki" is a folder of markdown.

It is architecturally identical to remote adapters. Skill code does not change. The capability manifest declares the limitations honestly: no multi-agent ecosystem, no external API access, no concurrent reader visibility.

Rationale

The split exists because forges differ in three dimensions that all leak into skills if not isolated. Capability surface (GitLab Premium projects vs Forgejo's labels-only) leaks if main skills assume features. Data model (folder-structured wikis vs flat-plus-sidebar) leaks if main skills choose paths. CLI shape (tea, glab, gh) leaks if main skills shell out directly. Without the contract, every main skill ends up with platform branches and the system can't move to a new forge without rewriting them all.

The contract being a document rather than code matters. Code couples — a shared library of "forge operations" would still know about the platforms it serves. A specification is something both sides reference but neither owns. The main skill writes against the contract; the adapter writes against the contract; they meet in the middle without depending on each other.

The local-fs adapter being first-class — not a fallback, not a degraded mode — has two consequences worth being explicit about. First, contract-level skill development doesn't need a real forge: build and iterate against local-fs, then validate against /tea-cli and /glab-cli. Second, projects that genuinely don't want remote tracking (privacy, exploration, throwaway work) can run the same pipeline. The architecture makes "no remote forge" a supported configuration rather than an edge case.

Capability declarations live in adapter SKILL.md files rather than in CLAUDE.md for a reason: CLAUDE.md shouldn't duplicate adapter knowledge. The project says which adapter is active; the adapter says what it can do. Main skills read both and reconcile — they check the manifest before relying on an operation, so a project switching from GitLab to Forgejo doesn't suddenly fail because the new adapter lacks a feature the skill used.

Open questions

  • The contract document hasn't been authored yet. The shape of operations is implicit in current skill code rather than explicit in _shared/forge-contract.md. This is the central migration task — see the migration section in the project architecture notes.
  • /tea-cli exists today as a CLI reference rather than a full capability adapter. Expanding it into a contract-implementing adapter (with a published manifest, polyfills, and wiki rendering) is part of the same migration.
  • /glab-cli does not yet exist; needs to be authored before MedQAIR can migrate off /devwork/.