Skip to main content
A harness is the first thing the model sees in every conversation your app starts. It declares who you are, what your app surface can do, and which tools the model is allowed to call. Without a harness, the model has no idea whether it’s running inside a photo editor, an inventory tracker, or a general-purpose chat shell. By providing one, you prevent the model from inventing capabilities you haven’t enabled and stop it from presenting itself as a different Codex surface.

What a Harness Contains

A ChappieHarness value packages six fields. The SDK applies this context automatically at the start of every conversation so you don’t have to manage it manually.
name
String
default:"Chappie iOS Harness"
A display name that identifies this harness. The model uses it to refer to the current surface.
summary
String
A one-line description of what the app surface does. Keep it short and factual.
instructions
String
default:"ChappieHarness.defaultInstructions"
System-level instructions appended to every request. The SDK ships a default guardrail that prevents the model from claiming to be the Codex desktop app or accessing undeclared capabilities. Override this only if you have a good reason to replace the built-in guardrail entirely.
capabilities
[String]
A list of plain-English strings that tell the model what the host app has wired up. The model will only claim to support capabilities that appear here.
tools
[ChappieHarnessTool]
default:"[]"
Declared tools the model can call. Each entry names a function and describes what it does. Register tool handlers separately via ChappieHostTool — the harness declaration is the model-facing manifest; the host tool is the Swift handler that runs it.
plugins
[ChappieHarnessPlugin]
default:"[]"
Declared plugins available in this surface. Each plugin has a name, description, and optional version.

The Default Harness

ChappieHarness.default is a ready-made harness that works for general-purpose assistant surfaces. It carries the built-in guardrail instructions, four standard capabilities (multi-turn transcript, streaming responses, model selection, usage-limit awareness), and empty tool and plugin lists. Use it whenever you don’t need to customise the context.
// These two lines are equivalent:
let client = Chappie.client()
let client = Chappie.client(harness: .default)

Creating a Custom Harness

Declare a harness that matches your app’s actual surface, then pass it to Chappie.client(harness:).
let harness = ChappieHarness(
    name: "Inventory Harness",
    summary: "Native iOS surface for inventory questions and app context.",
    capabilities: [
        "multi-turn transcript",
        "streaming responses"
    ]
)
let client = Chappie.client(harness: harness)
For rapid prototyping, you can pass a raw string literal. The SDK wraps it in an "Inline Harness" with no declared capabilities or tools.
// String literal — good for quick experiments
let pirateClient = Chappie.client(harness: "You're a pirate. Speak like it.")

// Full default harness
let defaultClient = Chappie.client(harness: .default)
ChappieHarness.none is a harness with all fields empty. It disables harness injection entirely, which means the model receives no surface context. Use it only in test scenarios where you want a completely clean transcript.

Ready-Made Sample Harnesses

ChappieHarnessSamples ships four harnesses you can use directly or adapt as starting points:

.currentScreen

Declares read_current_screen — returns app-provided text and state for the currently visible screen. Useful for context-aware in-app assistance.

.documents

Declares read_selected_document_text — returns the user-selected document text and lightweight metadata. Built for document editing surfaces.

.photos

Declares describe_selected_photo — returns app-provided metadata or a safe description for the selected photo. Scoped to app-owned assets only.

.inventory

Declares lookup_item — looks up one inventory item by SKU. A good starting point for retail or warehouse apps.
Use them like any other harness value:
let client = Chappie.client(harness: ChappieHarnessSamples.inventory)

Declaring Tools in a Harness

When you want the model to be able to call a function your app implements, add a ChappieHarnessTool entry to the harness and register the matching Swift handler when you create the client. The harness declaration tells the model what the tool does; the host tool provides the runtime implementation.
let harness = ChappieHarness(
    name: "Inventory Harness",
    summary: "Native iOS surface for inventory questions and app context.",
    capabilities: [
        "multi-turn transcript",
        "streaming responses",
        "inventory lookup"
    ],
    tools: [
        ChappieHarnessTool(
            name: "lookup_item",
            description: "Looks up one inventory item by SKU."
        )
    ]
)

let client = Chappie.client(
    harness: harness,
    tools: [
        ChappieHostTool(name: "lookup_item") { arguments in
            // Return a result string based on arguments
            return lookupItem(sku: arguments["sku"] as? String ?? "")
        }
    ]
)
Keep ChappieHarnessTool.description concise and action-oriented. The model uses it to decide when and whether to call the tool, so a clear description produces more reliable calling behaviour.
For full details on registering handlers, providing approval flows, and handling tool errors, see the Host Tools guide.