Forgejo Accelerated

# Concepts

A theatre metaphor to help orient the reader:

  • Human as the Author: the author & benefactor of the production.
  • Forgejo as the Stage: where the production plays out.
  • fjx as the Director: executes the author's vision by keeping agents on-script.
  • Prompts as Scripts: the roles that agents adopt.
  • Agents as Actors: perform under the fjx's guidance but with room to improvise.

The three sections below cover the three load-bearing layers in order: the stage, the director, the actors.

# Forgejo

Forgejo is the durable stage for humans, actors, and fjx to perform on.

# Why?

The temptation in agent-assisted systems is to invent an out-of-band coordination layer — a message queue, a Redis hash, a workflow engine. Each one adds a place where the workflow exists outside the artifacts humans review. FJX refuses that. The cost is that some operations are awkward to express in issue-and-comment primitives; the benefit is that there is one place to look, one place to debug, and one place where authority is exercised.

When a human takes over from a stalled agent, there is no state to recover. The issue is the state.

# State

Forgejo is the system of record. Everything durable lives there: issues, pull requests, comments (including the per-role agent ledgers), labels, assignees, the project wiki, Actions run history. There is no external database. If it isn't in Forgejo, it doesn't exist as far as the workflow is concerned.

This is deliberate. Every artifact is something a human can open in a browser and read. Every state change leaves a trail in the issue timeline. When the workflow misbehaves, the diagnostic surface is the same one the agent saw.

# Coordination

Forgejo is also the shared workspace humans & agents both act on. The control primitives are Forgejo-native:

  • Labels record state. agent/working, agent/review, agent/blocked, agent/new.
  • Assignees route work. Dispatch is by assignment: assignee=agent-dev means dev picks it up next. The agent-<role> accounts are real Forgejo users.
  • Comments with stable markers carry per-role artifacts. PM briefs (<!-- pm:brief:dev -->), agent ledgers (<!-- agent-pm:ledger -->, <!-- agent-dev:ledger -->, <!-- agent-qa:ledger -->).
  • /<command> directives in comments encode human authority. /spec-approved, /needs-spec, /block <reason> — interpreted by agent-pm, gated by a trust map.
  • Actions run on PR events and produce the evidence agent-qa consumes.

What Forgejo is not: an active control plane. Nothing in Forgejo reconciles agent state. The agents poll for work (fjx dev next, fjx pm tick) and act. Forgejo just holds the state legibly while they do.

# fjx

fjx is the opinionated CLI that agents & humans drive against Forgejo. fjx is to Forgejo what kubectl is to a Kubernetes cluster: the cluster exposes APIs; kubectl gives you a workflow-aware CLI that bakes in conventions.

Every meaningful workflow step is a verb:

  • fjx dev next — pick the next issue ready for dev work.
  • fjx dev claim <N> — claim it (label, assign, create ledger — one atomic step).
  • fjx dev ledger --body-file ... --status review — update the ledger.
  • fjx pr create --title ... --body-file ... — open the PR (prepends Refs: #<N> from cache).
  • fjx dev done <N> — hand off (refuses to proceed if the ledger is still Status: working).
  • fjx pm tick — run a PM cycle, return JSON of issues that need attention.
  • fjx pm close <N> — finalize a closed-PR issue.
  • fjx qa checks <pr> — fetch the Actions workflow runs for a PR's head commit.
  • fjx wiki set <slug> --body-file ... — upsert a page in the Forgejo project wiki.

Each verb is deterministic (same inputs, same effect), idempotent (safe to re-run), and audit-friendly (the command itself reads as documentation of what happened).

# Why?

fjx exists to make the agent's job easier. An agent that drives fjx dev claim 42 does not have to discover the API shape, sequence three calls in the right order, remember which label to apply first, or burn tokens reasoning about any of it. The built-in help serves as a crude form of discovery that agents can use. One short command does the right thing.

The guardrails and the audit trail fall out of that ergonomics as side effects:

  • Fewer tokens spent on plumbing. Agent reasoning context is finite. A single named verb keeps it focused on the work (what change does this issue need) instead of the mechanism (what JSON does this POST want). Multiply across every workflow step in a cycle and the savings are substantial.
  • Fewer ways to get the plumbing wrong. fjx dev claim <N> performs three coordinated operations atomically: apply agent/working, set assignee=agent-dev, upsert the ledger. An agent that hits the raw API can do those independently — miss one, do them out of order, or do two of them on the wrong issue. fjx removes that surface.
  • A trail a human can read and replay. A ledger entry plus fjx dev done 42 in shell history is legible. A sequence of POSTs to /api/v1/repos/... is not. The agent gets ergonomics; the operator gets auditability — same artifact.
  • One place to evolve the workflow. When conventions change (the ledger gets a new field, claim also writes to the PM brief), the change happens inside fjx and every agent inherits it on the next install. Encoded-in-prompts conventions drift; encoded-in-CLI conventions don't.

The prompts direct agents to use fjx and to treat fjx X --help as the first move when something errors — never curl against the Forgejo API directly. Not because the raw API is forbidden, but because reaching for it is almost always the agent paying tokens to redo work fjx already did, while losing the side-effect benefits in the process.

# What fjx is not

  • Not an orchestrator. fjx doesn't decide what to do next. The agent decides (reading its phase prompt); fjx just provides the verb.
  • Not an agent framework. fjx sits below the agent layer. Any process — human, LLM, shell script — can drive it.
  • Not a wrapper. A wrapper is a 1:1 mapping of API endpoints. fjx is a workflow vocabulary: many of its verbs bundle multiple API calls, and some have no direct API equivalent (e.g. fjx dev next reads the cache, queries Forgejo, ranks issues, and writes back the selection).

# Agents

The third layer is where work actually happens. Forgejo holds the state; fjx provides the verbs; agents are the actors that decide what to do and do it. They read the brief, exercise judgement, and act. The discretion is the point — fjx is the deterministic layer below them, and agents are everything that isn't deterministic.

# Context

Each role (pm, dev, qa, and eventually build) is an agent. An agent's operating context for a cycle is:

  • A bootstrap prompt read at the start of the cycle. Where to find ready work, how to claim it, where to look for further instructions.
  • One or more phase prompts that the brief routes the agent to. Dev has simple, investigate, propose, apply. Each phase has a different output shape and different scope rules.
  • A brief (PM-curated, scoped to one issue) that points the agent to the right phase prompt and adds the small amount of context the issue body and AGENTS.md don't already supply.

The bootstrap + phase + brief together are the agent's context for one cycle. No state persists in the agent across cycles. Every cycle reads the world from Forgejo, acts via fjx, and exits.

# Prompts

It's tempting to call prompts "the control layer." They aren't. Prompts express intent — what good work looks like for this role, what the failure modes are, what to escalate. Whether the agent follows that intent on any given cycle is a judgement call the agent makes. When the agent gets it wrong, the answer is usually to refine the prompt (sharpen the intent), not to add enforcement (a check that runs after the fact).

The taste lives in the artifacts the agent reads before it runs:

  • AGENTS.md — project-wide standing instructions.
  • src/prompts/*.md — bootstrap and phase prompts per role.
  • wiki/ — durable project memory the agent consults when relevant.
  • The brief-authoring guidelines in src/prompts/pm.md — what earns a Context bullet.

This is the senior-practitioner chair from Roles & Chairs: ship taste as artifacts the agent reads before it runs, not as runtime catches in review.

# Routing

A tempting design is to bake routing into the CLI — fjx dev next would inspect labels, decide the phase, and tell the agent what to do. FJX deliberately doesn't go there:

  1. Prompts are easier to revise than code. A prompt change is a markdown diff; a CLI change is a release. Taste evolves faster than CLIs should.
  2. The CLI shouldn't enforce judgement. Knowing whether an issue is "simple" or needs a spec is judgement, not a deterministic rule. fjx routes by labels and assignees (mechanical); the agent routes by reading the brief (judgement).
  3. Multiple agents, one CLI. fjx is shared across roles. Embedding DEV's decision tree in the CLI would couple it to a specific role's workflow. The current shape keeps fjx role-neutral: it provides verbs, the agents compose them.

# Failures

At this stage, FJX is biased towards identifying & filling gaps in the tooling & prompts, not towards maximizing productivity. Agents are instructed to report issues with the workflow and to block, not to attempt to workaround the issue and hit the REST API directly.

The prompts repeatedly tell agents: if fjx X errors or returns an unexpected shape, the default assumption is you invoked it wrong, not that fjx is broken. Next move is fjx X --help, never curl against the API.

This is the most-violated rule in early prompt iterations, and it's load-bearing. An agent that reaches for the raw API after one fjx error has done three damaging things at once: skipped the conventions, produced an action history no human can replay, and pattern-matched "tool is broken" when the actual signal was "I misused it." Fixing this is partly a prompt problem (named anti-pattern, evidence-required blocker checklist) and partly a fjx problem (better error messages, better --help, fewer surprising shapes).