astradevlabsastradevlabs
← All posts
Tutorials5 min

Step-by-Step Playbook: Put Codex and Claude Code Behind One HarnessAgent

Tutorials

Vercel's August 13 update matters for teams building coding agents: the AI SDK harness layer now supports ACP-compatible harnesses, which means the abstraction is no longer just about swapping today's adapters. It is becoming the stable seam between your product and whichever coding runtime you trust next.

If you want the smallest practical way to use that shift, build around HarnessAgent now, keep the sandbox boundary explicit, and treat the harness as a replaceable adapter.

1. Start with the stable abstraction, not a favorite harness

Vercel introduced HarnessAgent in June as one API for running established agent harnesses like Claude Code, Codex, and Pi. The key design point is simple: your app talks to one agent interface, while the harness package owns the messy layer above the model call: sessions, sandboxes, permission flows, skills, and runtime behavior.

The August 13 ACP update makes that abstraction more valuable, not less. If ACP-compatible harnesses can plug into the same layer, your app code should depend on the harness contract, not on one provider's custom runtime.

2. Install only the packages you actually need

The Vercel Knowledge Base guide uses the smallest real stack for coding-agent triage:

bash
pnpm add ai @ai-sdk/harness @ai-sdk/harness-claude-code @ai-sdk/harness-codex @ai-sdk/sandbox-vercel @vercel/sandbox

That is enough for a two-harness setup. Do not preinstall every adapter you might evaluate later. The whole point of the harness layer is that future swaps should be a package change, not an architectural rewrite.

If you are using Next.js, keep these packages external to the server bundle, exactly as Vercel's guide recommends:

ts
const nextConfig = {
  serverExternalPackages: [
    '@ai-sdk/harness',
    '@ai-sdk/harness-claude-code',
    '@ai-sdk/harness-codex',
    '@ai-sdk/sandbox-vercel',
    '@vercel/sandbox',
  ],
};

3. Put authentication through one gateway path

One of the cleaner details in Vercel's guide is that the harness adapters authenticate through AI Gateway using VERCEL_OIDC_TOKEN. That removes the usual provider sprawl. You do not need one Anthropic key path for Claude Code and a different OpenAI key path for Codex in the application layer.

For local development, Vercel's documented flow is:

bash
vercel link
vercel env pull

Then the app reads VERCEL_OIDC_TOKEN locally. That gives you one credential path for model access while keeping the harness choice separate.

4. Make the sandbox the default, not the upgrade

The best part of the Vercel pattern is not model flexibility. It is that unknown code runs in Vercel Sandbox, not on the maintainer's machine. Their issue-triage example creates the agent with createVercelSandbox({ runtime: 'node24' }) and only the ports it needs.

That is the right default for any workflow that touches third-party repositories, reproduction cases, or generated code you would not casually run on a laptop.

The smallest useful setup looks like this:

ts
import { HarnessAgent } from '@ai-sdk/harness/agent';
import { createClaudeCode } from '@ai-sdk/harness-claude-code';
import { createVercelSandbox } from '@ai-sdk/sandbox-vercel';

const agent = new HarnessAgent({
  harness: createClaudeCode({ auth: { gateway: process.env.VERCEL_OIDC_TOKEN } }),
  sandbox: createVercelSandbox({ runtime: 'node24', ports: [3000] }),
  instructions: 'Investigate the repo safely and report findings only.',
});

You can swap the harness factory and keep the rest of the flow intact.

5. Keep the harness switch as one function

Vercel's guide is explicit about this: Claude Code and Codex adapters are constructed with the same shape, so the real difference at the call site is which factory you resolve.

That means your code should centralize harness selection behind one function and return a configured adapter. Do not scatter provider-specific conditionals through route handlers, prompts, or UI state. That is exactly the portability tax the harness layer is supposed to remove.

A minimal resolver is enough:

ts
function resolveHarness(kind: 'claude-code' | 'codex') {
  if (kind === 'claude-code') return createClaudeCode({ auth: { gateway } });
  return createCodex({ auth: { gateway } });
}

When ACP-compatible harnesses become part of your evaluation set, this is the seam you extend.

6. Put the workflow contract into a skill or fixed prompt

The Vercel issue-triage guide uses a narrowly scoped skill: treat the repository as untrusted, avoid remote side effects, run the failing command first, and return a concise report. That is the right pattern. The harness should be interchangeable, but the task contract should stay stable.

In practice, that means you should lock down things like:

  • read-only by default unless a patch is explicitly requested
  • no pushing branches or opening pull requests automatically
  • bounded logs and report-shaped output
  • the first command to try before exploratory behavior begins

This is what keeps harness swaps operationally boring.

7. Stream results, not just final text

HarnessAgent.stream() is not just a convenience. It is how you make debugging and product UX tolerable. Vercel's route example emits newline-delimited JSON with report, error, debug, and activity events so a frontend or worker can render progress separately from the final maintainer report.

That matters even more once you test multiple harnesses. If Codex and Claude Code both produce a final answer, but one takes a riskier setup path or gets stuck longer in tool activity, you want that visible in your telemetry without rewriting the application surface.

8. Build for today's adapters, leave room for ACP tomorrow

The practical takeaway from the August ACP update is not that you should immediately chase every compatible runtime. It is that you should stop wiring your product around one harness vendor's assumptions.

Build the app around four stable pieces instead:

  1. HarnessAgent as the execution boundary.
  2. Vercel Sandbox as the default safety boundary.
  3. AI Gateway auth as the credential boundary.
  4. A narrow task contract as the behavior boundary.

If you do that, swapping Claude Code for Codex is already cheap today, and evaluating ACP-compatible harnesses later becomes an adapter exercise instead of a rebuild.

References