Inspiration

When OpenAI released Symphony, I became fascinated by Harness Engineering: not just giving an agent a prompt, but designing the environment, workflow, constraints, evidence, and feedback loops that help it do reliable work.

At the same time, I was constantly changing context. I work across multiple clients, projects, and teams. One engagement might be a small proof of concept; another might involve a production web application, data migration, ransomware exercises, or near-digital-twin simulation scenarios. Outside client work, I also maintain several personal Swift applications and side projects. There is no single development process that fits all of them!

Sometimes I want a lightweight, exploratory workflow close to “vibe coding.” Sometimes I need structured, spec-driven development with explicit review gates. Some situations demand stronger isolation, evidence, recovery, and human approval. Others need the process to become simpler and faster. The right workflow depends on the project, the team, the risk, and the delivery.

That led me to JAF Forge and the idea of Graph Engineering: define the development process itself as a versioned graph, then run coding agents through it.

## What it does

JAF Forge is a local-first Graph Engineering harness for coding agents working against real Git projects.

A YAML workflow defines the graph: its phases, steps, agent profiles, actions, gates, evidence requirements, and allowed transitions. JAF Forge validates that graph, stores its operational state locally, and presents it through both a callable CLI and a native macOS application.

Work items move through the graph only through explicit, typed operations. Coding agents run inside isolated, owned workspaces. Their runs produce durable evidence and structured handoffs. If a run is interrupted or the application restarts, the work remains visible with explicit recovery options.

JAF Forge also keeps three important decisions separate:

  • advancing a work item through its workflow;
  • authorizing a privileged host action;
  • answering an agent-level permission request.

Accepting one does not silently approve the others.

The result is not another task manager or a collection of prompt templates. It is a harness for designing and operating different software-delivery graphs while keeping execution observable, recoverable, and under human control.

## How I built it I built JAF Forge in modern Swift with strict concurrency. Its central boundary is an in-process engine, JAFEngine, backed by SQLite. Both the CLI and the SwiftUI application consume the same typed engine operations, so the UI never becomes the only way to perform or understand an important action.

I separated state according to ownership:

  • Git stores project-owned workflows, specifications, decisions, and code.
  • SQLite stores local harness state, workflow history, runs, approvals, and audit records.
  • Run-artifact directories store evidence, validation output, handoffs, and diagnostic material.
  • Secrets remain under host control and are referenced rather than copied into project files or agent prompts.

I used Spec Kit to build the project as a sequence of small vertical slices. When behavior was uncertain, I ran probes before implementing it. I recorded architectural decisions in ADRs, wrote acceptance criteria and tests, and used isolated Git worktrees for implementation.

Codex worked inside bounded implementation lanes and produced durable handoffs. I retained responsibility for deciding scope, designing the architecture, approving plans, reviewing the implementation, resolving conflicts, verifying evidence, and determining whether a slice was actually complete.

The process became a form of dogfooding: I was using workflow graphs, isolated agents, evidence gates, and explicit decisions to build the harness that provides those same capabilities.

## Challenges I ran into The hardest challenge was creating flexibility without vagueness.

A graph must be configurable enough to support very different projects, but constrained enough that JAF Forge can validate it, explain it, recover it, and refuse unsafe transitions. It cannot become a generic workflow engine where every behavior is hidden inside arbitrary scripts.

Recovery was another major challenge. A successful terminal command is not proof that an agent completed its work correctly. Runs need durable identities, owned workspaces, bounded artifacts, explicit handoffs, and recovery behavior for interrupted processes, stale worktrees, missing evidence, application restarts, and computer reboots.

The UI also had to remain honest. It could not invent state, hide failures, or implement operations that did not exist outside the app. Every state-changing control needed a corresponding engine operation and callable front.

Finally, the project had to manage the same complexity it was created to solve. As the architecture became clearer, I had to evolve JAF Forge’s own specifications, gates, agent roles, worktree discipline, evidence, and recovery practices without losing the work already completed.

## Accomplishments I’m proud of I am proud that JAF Forge is a working harness rather than only a workflow proposal.

It can validate versioned YAML workflows, manage durable work items, prepare typed agent actions, run agents through isolated workspaces, collect evidence, pause for explicit decisions, recover interrupted work, and present the same underlying operations through a CLI and a native application.

I am especially proud of the decision boundaries. Workflow transitions, privileged actions, credentials, and agent permissions remain separate instead of collapsing into one broad “approve” button.

I am also proud that the board is a projection of durable engine state. The application can show workflow phases, steps, active work, completed work, fan-out lineage, reviews, runs, and recovery conditions without becoming a second source of truth.

Most importantly, I built JAF Forge using the principles it is meant to enforce: small slices, explicit graphs, isolated agents, durable evidence, human decisions, and recovery when the original plan met reality.

## What I learned I learned that reliable agent development is less about finding one perfect prompt and more about engineering the graph around the agent.

The graph determines what context is available, what actions are legal, what evidence is required, when a human must decide, and how the system responds when something fails.

I also learned that observability and recovery cannot be added at the end. If identity, evidence, and interruption handling are not part of the original operation, reconstructing trustworthy history later becomes much harder.

Most of all, I learned that different projects genuinely need different levels of structure. The goal should not be to force every team into one “best” process. The goal should be to make the chosen process explicit, executable, inspectable, and adaptable.

That is what Graph Engineering means to me.

## What’s next for JAF Forge: The Graph Engineering Harness Next, I want to make the graph easier to see, author, and operate without weakening its safety boundaries.

That includes deeper work-item event and finding history, bounded and redacted live run logs, a more refined native JAF Studio experience, and better diagnostic and evidence views. I also want to improve the installation and demonstration path so a developer can evaluate JAF Forge quickly without configuring every live integration.

Beyond that, I want to explore safe parallel agent execution across independently owned worktrees, richer graph-authoring workflows, and more replaceable project-management projections while keeping JAFEngine, SQLite, and the project’s YAML workflow authoritative.

The long-term goal is not one universal software-development workflow. It is a harness that lets each project define the graph it actually needs.

** Build the graph. Run the work. Keep the proof.**

Built With

Share this project:

Updates