Projects

Example workflows

Complete WORKFLOW.md files you can copy, from a ClickUp sprint in Docker behind LiteLLM to a GitHub repository on Cloudflare.

Each example is a complete file. Copy one into your repository's root as WORKFLOW.md, replace the placeholders, and check the Workflow tab's inspector for anything still unset.

ClickUp sprint, Docker, LiteLLM gateway#

A web app whose tasks come from the current ClickUp sprint. Agents run in Docker, route model traffic through a LiteLLM proxy with per-task spend tags, test the app in a browser, and open draft pull requests on GitHub.

Set these first:

  • CLICKUP_API_TOKEN in Settings → Environment (the wizard does this for you).
  • LITELLM_API_KEY, a LiteLLM virtual key with a budget, in Edit Project → Environment, so this project has its own key and budget.
  • The agent and browser images, from Sandboxes.
WORKFLOW.md
---
# SI Fabrik · Symphony workflow for shop-storefront
tracker:
  kind: clickup
  provider:
    api_token: $CLICKUP_API_TOKEN       # Settings → Environment
    sprint_folder_id: "90120000000"     # Sprints folder: tasks from the current sprint (auto-rolls over)
    assignee: me                        # only tasks assigned to the token's owner
  active_states: ["to do", "in progress"]
  terminal_states: ["complete", "closed"]
  required_labels: [agent]              # only tasks tagged "agent" are dispatched

polling:
  interval_ms: 15000

workspace:
  root: ~/HarnessWorkspaces/shop-storefront

git:
  base: main
  save: true
  push: true
  remote: origin
  pull_request: draft

hooks:
  timeout_ms: 120000

agent:
  max_concurrent_agents: 3
  max_turns: 12
  max_retry_backoff_ms: 300000

limits:
  daily_budget_usd: 40
  max_cost_per_issue_usd: 12
  max_attempts_per_issue: 4
  pause_after_consecutive_failures: 5

runner:
  kind: claude_code

claude:
  command: claude
  model: claude-opus-5-5
  permission_mode: bypassPermissions
  effort: high
  max_budget_usd: 6

codex:
  turn_timeout_ms: 3600000
  stall_timeout_ms: 600000

docker:
  enabled: true
  image: harness-agent:latest
  memory: 6g
  cpus: 4

gateway:
  enabled: true
  base_url: http://localhost:4000       # rewritten to host.docker.internal inside Docker
  api_key: $LITELLM_API_KEY             # project variable: its own LiteLLM budget
  models:
    opus: claude-opus-5-5
    sonnet: claude-sonnet-5-5
    haiku: claude-haiku-5-5             # set it: Claude Code uses Haiku for background tasks
  headers: { X-Team: storefront }
  tags: true                            # x-litellm-tags: harness,project:shop-storefront,issue:<id>

browser:
  enabled: true
  viewport: 1440x900

preview:
  setup: npm ci
  command: npm run dev -- -H 0.0.0.0
  port: 3000
  ready: /api/health
  ready_timeout_s: 300

sandbox:
  network:
    allow: [api.stripe.com, "*.storefront-staging.example.com"]
---
You are an autonomous senior engineer working on **{{ issue.identifier }}: {{ issue.title }}**.

{% if attempt %}
> This is attempt {{ attempt }}. Read the ClickUp comments and the workspace to see what was already done.
{% endif %}

{{ issue.description | default: "_No description provided._" }}

1. Read `AGENTS.md`, then plan before editing.
2. Implement the change with tests. Run `npm run lint` and `npm test`.
3. Check user-facing changes in the browser at http://localhost:3000 and save screenshots under `.harness/artifacts/`.
4. Commit on this branch. Don't push or open pull requests yourself.
5. When it's done and verified, move the task to **review** with `clickup_set_status` and comment with a Markdown
   summary: what changed, how you verified it, what to look at. It becomes the pull request description.
6. If you're blocked, say why in a comment and stop.
Tip

required_labels is a cheap way to roll out agents gradually: only tasks someone tagged agent are picked up.

Built-in board, no sandbox#

The smallest useful setup, for a trusted repository on your Mac. Agents run on the host with your Claude login.

WORKFLOW.md
---
tracker:
  kind: local
  provider:
    path: .symphony/board.json
    prefix: DOC
  active_states: [Todo, In Progress]
  terminal_states: [Done, Canceled]
  board_states: [Backlog, Todo, In Progress, Human Review, Done, Canceled]

workspace:
  root: ~/HarnessWorkspaces/docs-site

git:
  pull_request: off          # keep task branches in this repo; no push

agent:
  max_concurrent_agents: 2
  max_turns: 10

docker:
  enabled: false
---
Work on **{{ issue.identifier }}: {{ issue.title }}**.

{{ issue.description }}

Commit your change. When done, move the issue to **Human Review** with `board_set_state` and comment with a summary.
Warning

Without a sandbox, bypassPermissions lets the agent run any command as you, without asking. The inspector warns about this. Use it only for repositories you trust.

GitHub Issues on Cloudflare#

Issues labelled agent in a GitHub repository, with workspaces in Cloudflare Containers. Model keys and the GitHub token stay on your Mac or server; the sandbox only sees a placeholder.

WORKFLOW.md
---
tracker:
  kind: github
  provider:
    repo: your-org/api-service
    token: $GITHUB_TOKEN                 # falls back to `gh auth token`
    exclude_labels: [human-review, blocked]
  active_states: [open]
  terminal_states: [closed]
  required_labels: [agent]

workspace:
  root: ~/HarnessWorkspaces/api-service

git:
  base: main
  pull_request: ready

agent:
  max_concurrent_agents: 4
  max_turns: 15

docker:
  env: [SENTRY_DSN]                    # host variables passed into the sandbox, by name

sandbox:
  provider: cloudflare                 # bridge URL and token in Settings → Sandbox
  network:
    allow: [pypi.org, files.pythonhosted.org]
---
You're fixing GitHub issue {{ issue.identifier }}: {{ issue.title }}.

{{ issue.description }}

Run `make test` before you hand off. When it's done, comment with `github_comment` and add the
`human-review` label with `github_add_labels`.

GitHub boards are read-only in SI Fabrik; the hand-off is the human-review label, which also stops the issue from being dispatched again.

Codex runner#

The same idea with Codex. Approvals are accepted for the session; the policies are passed through to Codex unchanged.

WORKFLOW.md
---
tracker:
  kind: local
  active_states: [Todo, In Progress]
  terminal_states: [Done, Canceled]

workspace:
  root: ~/HarnessWorkspaces/cli-tool

runner:
  kind: codex

codex:
  command: codex app-server
  model: gpt-5.5-codex
  approval_policy: never
  thread_sandbox: workspace-write
  turn_timeout_ms: 3600000
  stall_timeout_ms: 600000

docker:
  enabled: true

git:
  pull_request: draft
---
Implement {{ issue.identifier }}: {{ issue.title }}.

{{ issue.description }}

When finished, move the issue to **Human Review** and comment with what you changed.

Codex in Docker needs an OpenAI API key in Settings → Credentials, or a gateway.

A library shared with an app#

Two projects: shared-lib publishes code, shop-storefront uses it from source and may file tasks in it.

shared-lib/WORKFLOW.md (front matter excerpt)
share_with: [shop-storefront]     # shop-storefront may use this project's code and app
accept_tasks_from: [shop-storefront]   # its agents may file tasks here
linked_tasks_state: Backlog       # a person approves them before an agent runs
shop-storefront/WORKFLOW.md (front matter excerpt)
links:
  packages:
    - name: "@your-scope/shared"
      from: source
      project: shared-lib
      ref: main
  services:
    - name: api
      env: API_URL
      url: https://staging-api.example.com

See Project links and Linked tasks.

See also#