JJETSYNGet in touch

Build an AI employee

Author a new AI employee as plain Claude Code files, with no compile step: the folder layout and its pieces, the hello-world minimal example, roles versus template agents, and the one-employee-many-businesses config model.

A Jetsyn AI employee is authored as plain, vanilla Claude Code files. There is no compile step and no framework to learn: an employee is one self-contained folder. You copy the reference folder, rename it, and grow the pieces. This page is the folder layout, the smallest working example, and the recipe to build your own.

An employee is one folder#

Every employee is a single portable folder. The reference starter, hello-world, is the smallest real one, so its layout is the layout every new employee copies. The same shape scales from a one-step employee to a full multi-stage one. Only the contents change.

the employee folder (copy this shape)
my-employee/                     # the employee = one portable folder
  my-employee.md                 # 1. DEFINITION: persona + frontmatter the CLI reads
  SKILL.md                       # 2. SKILL: the operator manual for the scripts
  scripts/
    do_thing.py                  # 3. SCRIPT(S): deterministic tools (stdlib, dry-run default)
  workflows/
    my-employee.workflow.js      # 4. WORKFLOW: how the orchestrator runs it
  ui/
    MyEmployeeTile.tsx           # 5. UI: the dashboard tile (live state only)
    MyEmployeeTile.INSTALL.md    #        how to wire the tile into the app
  README.md                      # documents the folder

The pieces map onto vanilla Claude Code locations. Claude Code discovers definitions in .claude/agents/ and workflows in .claude/workflows/. The folder is the canonical source, and when an employee is seeded into a cell the definition and the workflow are projected into those standard locations. The definition and the skill are the core; the script, the workflow, and the tile are added as the employee needs them.

PieceWhat it isRole
`<name>.md`The definition: frontmatter (name, description, tools, model) plus the persona body and its portable docs. The CLI discovers it in .claude/agents/.Core
`SKILL.md`The operator manual for the scripts: the exact commands, the flags, and the safety rules. Frontmatter carries name, description, and allowed-tools.Core
`scripts/`The deterministic tools the employee drives. Standard library only, and safe by default: a real-world action stays a dry run unless a live gate is set.Optional
`workflows/<name>.workflow.js`How the orchestrator runs the employee. Exports a meta block, then calls agent() / phase() / log().Optional
`ui/<Tile>.tsx` + `.INSTALL.md`The dashboard tile: renders the employee's live state, white-label, plus its install recipe for the app.Optional

Keep the name identical

The folder name, the name in the definition frontmatter, the workflow's meta.name, and the tile id must all match exactly. They are matched by string, not validated, so a mismatch fails to render rather than raising an error.

The definition frontmatter

<name>.md is the employee: YAML frontmatter the CLI reads, then the persona body and its portable docs, kept in the same file so the employee travels as one unit. tools grants least privilege, and model: inherit takes the cell's model.

hello-world.md (frontmatter)
---
name: hello-world
description: >-
  The reference starter agent that sends ONE email. The smallest real
  end-to-end Jetsyn employee, and the canonical worked example of how an
  employee folder is built (definition + skill + script + workflow + UI).
  Copy this folder to start a new employee.
tools:
  - Read
  - Write
  - Bash
model: inherit
---

The skill frontmatter

SKILL.md is the operator manual for the employee's scripts. Its description is the auto-trigger surface, so write it keyword-rich: it is how the runtime decides when this skill applies. allowed-tools is a comma list.

SKILL.md (frontmatter)
---
name: hello-world
description: The reference starter agent that sends ONE email. The smallest real
  end-to-end Jetsyn employee. Use when the user says "hello world agent", "send a
  test email", "the starter agent", "how do I build an agent", or "scaffold a new
  agent". Composes a short message and dispatches it through Resend, safe by
  default (a dry run unless a live send is explicitly gated).
allowed-tools: Read, Write, Bash
---

Roles and template agents#

An employee registers as one of two provenance classes. The only difference is how the source file reaches a customer cell, copied or referenced. You choose by whether the customer may hold a readable copy of the source.

Role (white-label)Template agent
RegistrationAdd the name to ROLE_NAMES.Add the name to TEMPLATE_AGENT_NAMES.
Projection into a cellCopied into the cell's .claude/agents/*.md.Symlinked to the one canonical source folder.
Choose whenThe customer may hold a readable copy.The source stays the platform's (IP protection).

Both classes run on one shared house-rules floor that is appended to every employee's prompt on every run. A role or a workspace can narrow that floor, for example remove a tool, but nothing can widen it: tool limits only ever tighten.

Hello world: the smallest real employee#

hello-world does the smallest real thing an employee can do end to end: compose one email and send it, through Resend, safe by default. It has all the pieces in their smallest form and no business logic, so you can read it top to bottom in a few minutes and then copy it. A workflow instantiates it, the employee composes a short message, and it dispatches through a real channel script.

The script is a dry run by default. It composes and prints exactly what it would send, and touches no network:

dry run (always safe)
python3 scripts/send_email.py \
  --to you@example.com \
  --subject "Hello from Jetsyn" \
  --body "Hi there. This is the Hello World agent saying hello."

It prints one JSON object with dry_run: true and a would_send block showing the exact message. To send for real, both gates must hold: you pass --live and RESEND_JETSYN_API_KEY is set in the environment. Miss either and it stays a dry run.

Safe by default is the contract

Any script that takes a real-world action (a send, a spend, a write outside the cell) must default to a dry run and open the live path only on an explicit flag plus a required env var. Never set that gate for the user: surface the exact live command and let a human decide. This double gate is the pattern every real employee follows, from hello-world to ai-sdr.

One employee, many businesses#

One employee folder serves many businesses by pointing it at a different config. The niche, the ICP, the offer, the sender identity, and the fixed next-step are runtime config, never code. The employee only ever knows field names, not field values, so two configs produce two different behaviors with zero code change.

Each white-label employee reads its config slice from the cell's Brain/. That is why two tenants can run the same ai-sdr and get two entirely different outbound motions, and why a vertical is never baked into a script. Verticals appear only inside labeled example configs: you copy one and replace every value.

The config test

If two businesses' configs produce identical output, a value that should be config got baked into code. The pipeline should only ever know field names, not field values.

Build one: the recipe#

  1. 1

    Copy the reference folder

    Start from agents/templates/hello-world/. Rename every hello-world to your employee's name: the folder, <name>.md, the workflow file, the tile, and the ids inside them.

  2. 2

    Write the definition

    Grow <name>.md into your persona and boundaries. Set the frontmatter name (equal to the folder name), a keyword-rich description, a least-privilege tools list, and model: inherit.

  3. 3

    Grow the scripts

    Keep them standard-library only, with no pip install. Make any real-world action safe by default: it dry-runs unless a flag plus an env var open the live path. Document every flag in SKILL.md.

  4. 4

    Wire the workflow

    In workflows/<name>.workflow.js, export meta with name, description, whenToUse, and phases, then drive the run with agent(), phase(), and log(). The meta.name must equal the folder and definition name.

  5. 5

    Add the tile (optional)

    Drop ui/<Tile>.tsx and its .INSTALL.md. The tile renders the employee's live state off the event stream, white-label, with no business values baked in, and its install recipe wires it into the app.

  6. 6

    Register it

    Add the name to ROLE_NAMES (copied into cells) or TEMPLATE_AGENT_NAMES (symlinked to the source). There is no compile step: the seeder projects the definition into .claude/agents/ and the workflow into .claude/workflows/ in each cell.

The workflow is a small script. It exports a meta block that names the employee and its phases, then drives the run:

workflows/hello-world.workflow.js
export const meta = {
  name: 'hello-world',
  description: 'The reference starter workflow: the smallest real end-to-end run. An orchestrator kicks it off, then ONE agent composes an email and dispatches it, safe by default.',
  whenToUse: 'To learn or prove the orchestrator -> agent -> real-channel shape with the least surface, and as the copy-me start for a real workflow.',
  phases: [
    { title: 'Strategist', detail: 'the orchestrator kicks off the run and states the single step' },
    { title: 'Send', detail: 'the agent composes one email and dispatches it (dry-run unless the live gate is open)' },
  ],
}

Where to go next#