Auto Lab · DocsBack to app

Goal manifest

Every key in kortix.yaml, the goal manifest: agents, connectors, triggers, sandbox and env.

kortix.yaml at the root of the goal's repository is the goal manifest; the UI calls it the project manifest. It says which agents may run and what each may touch, which connectors and triggers the goal has, which machine sessions start on and which secret names the goal expects. This page is the reference for version 2, which every new goal uses.

Check the file

The schema is public. The first line of the example below points your editor at it. kortix validate checks the file in a clone, and kortix schema --version 2 prints the schema. The same check runs when a change request merges, and an invalid manifest blocks the merge. Top-level keys Auto Lab does not know are skipped rather than rejected, so the file can carry your own notes. A version higher than 2 is refused. Older goals may still have a version 1 kortix.toml; new goals never do.

A full example

# yaml-language-server: $schema=https://app.auto-lab.ai/schema/kortix.v2.schema.json
kortix_version: 2
default_agent: kortix

env:
  required: [CRM_API_KEY]
  optional: [FORM_WEBHOOK_SECRET]

sandbox:
  default: data
  templates:
    - slug: data
      name: Data tools
      dockerfile: .kortix/Dockerfile
      cpu: 4
      memory: 8

agents:
  kortix:
    connectors: all
    secrets: all
    skills: all
    kortix_cli: all
  reporter:
    connectors: [hubspot, gmail]
    connectors_required: [hubspot]
    secrets: [CRM_API_KEY]
    skills: [weekly-brief]
    kortix_cli: [project.read, project.gitops.push]

connectors:
  - slug: hubspot
    provider: composio
    app: hubspot
    policies:
      - match: "*delete*"
        action: block
  - slug: gmail
    provider: composio
    app: gmail
    authorization_strategy: user
    sensitive: true

policies:
  - match: "gmail.*send*"
    action: require_approval
policy:
  default_mode: risk

triggers:
  - slug: monday-brief
    name: Monday brief
    type: cron
    agent: reporter
    cron: "0 0 8 * * 1"
    timezone: Europe/London
    prompt: Draft this week's competitor brief and send it to me for review.
  - slug: new-lead
    type: webhook
    secret_env: FORM_WEBHOOK_SECRET
    filter:
      body.type: lead
    prompt: |
      New lead from {{ body.email }} at {{ body.company }}.
      Check it against our qualification rules.

The example assumes the repository has .kortix/opencode/agents/reporter.md, a weekly-brief skill and both secrets.

Top-level keys

KeyRequiredDefaultWhat it sets
kortix_versionyesMust be 2.
default_agentyesThe agent a session or trigger runs when it names none. Must be a declared agent that is not disabled.
agentsyesWhat each agent may touch. At least one agent.
projectnoname and description, for people reading the file.
envnoThe secret names the goal expects.
sandboxnoAuto Lab defaultMachine images and which one sessions use.
connectorsnoThe tools agents can call.
policiesnoTool rules that apply across every connector.
policy.default_modenoallow_allWhat happens to a tool call no rule matches.
triggersnoScheduled and webhook automation.
opencode.config_dirno.kortix/opencodeWhere sessions read agents and skills. Leave it: the Chat and learning always use .kortix/opencode.
runtimenoopencodeLeave it unset. pi is an experiment behind a feature flag.
appsnoOnly read when the Apps feature is switched on for the goal. It is off by default.

A channels or sandboxes key is an error. Channels are connected in Settings › Channels, not in the file.

agents

agents maps an agent name to what it is allowed to touch. It holds no behaviour. The prompt, model, mode, temperature and tool permissions live in the agent's own file, .kortix/opencode/agents/<name>.md, and the map key must match that file name. Putting one of those fields in kortix.yaml is an error. See Agents and skills.

FieldDefaultNotes
(name)Lowercase letters, digits, - and _, up to 128 characters.
enabledtruefalse keeps the agent from starting.
connectorsnoneConnector slugs it may call, or all.
connectors_requirednoneConnectors that must have a working connection before a session starts. Each must also be in connectors.
secretsnoneSecrets it receives, by name, or all.
skillsnoneSkills it may load, by name, or all.
kortix_clinoneWhat it may do with the kortix CLI and the API, as a list of permissions, or all.
sandboxThe slug of the sandbox template its sessions start on.
workspacebranchbranch gives its sessions the repository on their own branch. runtime and read start them without a copy of the repository.

Grants are deny-by-default. A field you leave out means nothing is granted. all never lifts an agent above the person who started it. kortix_cli takes goal-level permissions only, such as project.read, project.gitops.push or project.trigger.read; run kortix validate --scopes for the full list. Organization permissions can never be granted to an agent. Even with project.gitops.merge, a session cannot merge a change request it opened.

The Chat's access to connectors follows the connectors grant of an agent named harness-main when the manifest declares one, and the grant of default_agent otherwise.

connectors

A connector is a tool agents can call. The definition lives in the file. The credential lives in Auto Lab and never in git. See Connectors.

FieldDefaultNotes
slugrequiredLowercase, unique among connectors. kortix_slack, kortix_teams and kortix_email are reserved for channels.
providerrequiredSee the next table.
namethe slugDisplay name.
enabledtrue
authorization_strategyprojectproject uses the goal's shared connection. user uses only the connection of the person the agent acts for.
sensitivefalsetrue makes every call ask first, reads included, unless a rule allows it.
policiesRules for this connector's tools. match is a pattern over tool names, action is always_run, require_approval or block.
authHow to send the credential: type (bearer, basic, api_key, custom, oauth1, hmac, aws_sigv4, mtls or none), in (header, query or cookie) and name for api_key and custom.
headersFixed request headers, up to 32. They are plain text in git, so never put a credential here.
ProviderNeedsNotes
composioappAn app from the connector catalogue, such as gmail.
pipedreamapp
mcpurltransport is http (default) or sse.
openapispecA URL or a path in the repository.
postmanspecA collection URL or path.
graphqlendpointspec is optional.
httpbase_urlspec is optional.
channelplatformslack, teams or email. Auto Lab writes these when you connect a channel.

Tool rules

Patterns use * as a wildcard and ignore case. A connector's own policies match its tool names. The top-level policies match <connector>.<tool> and apply to every connector. Auto Lab decides each call in this order, and the first answer wins:

  1. Top-level policies, top to bottom.
  2. The connector's policies.
  3. sensitive: true on the connector: ask first.
  4. policy.default_mode: allow_all runs the call. risk runs reads and asks before writes and deletes.

The Delegation dial writes these keys for you. Asks before acting adds a first rule that asks before every call and sets risk. Acts on its own removes that rule and sets allow_all. Acts within your rules puts your own rules and mode back. See Approvals and autonomy.

triggers

A trigger runs the agent on a schedule or when a signed HTTP request arrives. See Plans, schedules and triggers.

FieldDefaultNotes
slugrequiredLowercase, unique among triggers.
typerequiredcron, webhook or monitor.
promptrequiredThe message the agent receives. {{ … }} placeholders are filled from the payload.
namethe slugDisplay name.
agentdefault_agentMust name a declared agent. Leave it out rather than writing default.
enabledtruefalse keeps the trigger without firing it.
modelchosen when it firesPins a model, as provider/model. See Models.
session_modefreshWhich session a fire uses. See below.
filterPayload paths and the values they must equal, such as body.type: lead. A delivery that does not match is accepted and ignored.

Cron. Set cron to a six-field expression (second, minute, hour, day of month, month, day of week), or run_at to one ISO-8601 time for a single run. timezone is an IANA name and defaults to UTC.

Webhook. The URL is https://api.auto-lab.ai/v1/webhooks/projects/<goal-id>/<slug>. secret_env names the secret that holds the signing key. Sign the raw body with HMAC-SHA256 and send X-Kortix-Signature: sha256=<hex>; GitHub's X-Hub-Signature-256 also works. A sender that cannot sign can send the key itself in X-Kortix-Token or Authorization. The prompt can use {{ body.<path> }}, {{ headers.user_agent }}, {{ trigger.slug }} and {{ fired_at }}. The secret must be delivered to connectors only, never to a machine:

kortix secrets delivery FORM_WEBHOOK_SECRET none --consumer connector

Monitor. An always-on command from the repository whose output lines are events. Monitors are experimental and need the Monitors flag in Feature flags, which is off by default.

Session mode. fresh starts a new session on every fire. reuse sends each fire to the session this trigger started last, so context builds up; monitors use it by default. pinned uses the session in session_id. A session_key such as {{ body.chat_id }} keeps one session per value; an empty key falls back to fresh.

On a goal with the Chat, a webhook or monitor fire does not start a session. It wakes the Chat with the trigger's prompt and a summary of the payload. If the agent was not waiting for that event, the turn can only read, not act. Cron triggers still start a session, and those sessions count against Settings › Autonomy limits (New sessions per day, Sandbox minutes per day). The plan's routine and check-ups are not manifest triggers on these goals. They are the agent's own schedules in Brain › Schedules.

env

env.required and env.optional list names only. Values are secrets and never go in the file. Settings › Secrets lists the declared names so people know what to fill in; a missing required value does not stop a session. Names use letters, digits and _, do not start with a digit, are stored in upper case and fit in 64 characters. KORTIX_ names are reserved. An agent receives a secret only through its secrets grant.

sandbox

sandbox.templates is a list of machine images. Each entry takes these fields:

FieldNotes
slugRequired and unique. Up to 64 characters in practice. default is reserved.
nameDisplay name. Defaults to the slug.
dockerfileA path inside the repository. Set this or image, not both.
imageA public image with a pinned tag or digest, such as python:3.12-slim. latest gets a warning.
entrypointLeave it unset.
cpu, memory, disk1 to 32 vCPUs, 1 to 128 GiB of memory, 1 to 500 GiB of disk.

A value below the minimum is an error. A value above the maximum gets a warning and is capped. GPUs are not supported. sandbox.default must name a template declared here, or default for the Auto Lab image. An agent's own sandbox key wins over it. For Dockerfile rules and rebuilds, see Sandbox templates.

When changes take effect

  • A change in a session or a clone takes effect once its change request merges into the default branch. New sessions start from that branch, and the Chat picks the change up within about a minute.
  • A change saved in the UI (a trigger, a connector, a tool rule, the Delegation dial) is committed to the default branch at once. Auto Lab rewrites the file from its parsed contents when it saves, so comments are dropped and kortix_version moves to the top.
  • A webhook trigger answers 404 until its entry is on the default branch and enabled.
  • A sandbox change builds a new image. Running sessions keep the machine they started on.
  • A secret value is read when a machine starts, so it applies to the next session.