The open-source kortix.yaml behind a Slack agent
A Slack agent in Kortix is configured in kortix.yaml, and four blocks cover the whole job: the manifest head, the agent’s grant, the policy and the approvals TTL. Kortix is the open-source AI Operating System: your agents, their skills, your company memory, and every connector in one git repo you own, with the agents working on real cloud computers.
The manifest head and the agent grant
# yaml-language-server: $schema=https://kortix.com/schema/kortix.v2.schema.jsonkortix_version: 2default_agent: kortix agents: kortix: file: agents/kortix.md connectors: all secrets: all skills: all kortix_permissions: all
Source: https://kortix.com/docs/project/manifest
What each of the four blocks decides
The first three lines fix the file's version and its default agent. The schema line is a comment a YAML editor reads, which is why the editor can validate each key as you type and complete it for you. kortix_version: 2 picks the schema under which an agent's behavior lives in agents/<name>.md and its governance lives here. default_agent: kortix names the agent that takes a Slack message when nothing else names one.
Under agents:, each name maps to a grant. file points at the markdown holding the prompt and the model. connectors, secrets, skills and kortix_permissions are grant sets, and each takes all, none or a list of names. Read connectors: all as every connector the project declares, and secrets: all as every secret in it. The line is short, and it is the whole answer to "what can this thing reach".
A list narrows that reach to the slugs on it. An omitted connectors, secrets or kortix_permissions grant means none. skills is the exception: omit it and the permission.skill rule in the agent .md still decides. One grant is implicit: the channel connector that started a session is always callable from that session, so the Slack bot can answer in the thread it was mentioned in without a connector line of its own.
The policy block, and the calls that wait
policy and policies decide which connector calls run and which stop for a person. policy.default_mode covers a call that no rule matches, and it falls back to allow_all. Set it to risk and a read runs while a write or destructive call needs approval.
policy: default_mode: riskpolicies: - match: gmail.send_email action: require_approval
policies holds project-wide rules. A rule matches a fully qualified tool path, <connector-slug>.<tool>, with globs, and the first match wins. Project rules are checked before a connector's own rules, so a manifest rule can close a gap that a connector leaves open. Approval gates you set. Off until you set them.
A held call returns 202 with status: "pending_approval" and nothing ran (Kortix docs). approvals.ttl sets how long it waits: an integer with m, h or d, clamped between 5 minutes and 30 days, and 24 hours when the key is absent or the value is malformed.
approvals: ttl: 4h
A call nobody decides expires. It leaves the review queue, the card in the Slack thread shows Expired, and the agent asks again with a new call. Shorten the TTL on a busy channel and approvals time out faster than the people on shift can answer.
What a change request review catches
The manifest takes effect when it reaches the default branch. A dashboard, API or --apply edit commits there at once. Any other edit waits for kortix ship, a direct push or the merge of a change request. Session work reaches main through a change request. Merge is default-deny for agents.
That split is why the file is worth reading in review. A diff of kortix.yaml is small, and each hunk names its own consequence. A grant line that goes from a list to all widens what the agent reaches. A require_approval rule that disappears turns a held write into an unattended one. An approvals.ttl that drops from 4h to 15m shortens how long a person has to answer. kortix validate runs the same schema check in kortix ship and in the change request merge check, and an error blocks the merge while a warning does not. It does not check policy or policies, so those two blocks need a reader.
An agent can edit its own configuration on its session branch and propose the change. A person approves it. The review is the control, and four lines of YAML are what that person reads.
What stays out of the file
env: declares the secret names the project expects, and the values live in Secrets, never in the manifest. A session receives a secret name only when the agent's secrets grant and the person who started the session both allow it. kortix validate reports an error when a name in that grant is missing from env. Connector credentials follow the same rule: the manifest never holds a credential.
A connectors: entry may carry static headers, and those values sit in git in plaintext, so a credential there is a leak rather than a configuration. auth is refused on a managed catalog or channel connector because the provider authorizes the account instead. The Slack bot token and its client secret never enter a sandbox and do not appear on the Secrets page.
How the Slack connector appears after you connect
Slack is a channel as well as a connector, and connecting it writes the connector entry for you. kortix_slack is a reserved slug. kortix connectors add slack is refused and points at kortix channels connect, and validation treats the slug as declared even before the entry exists. Kortix writes the Slack and email entries in kortix.yaml when you connect, and removes them when you disconnect.
A channel is not a manifest key. A version 2 or 3 manifest rejects a top-level channels block, so the workspace, the bot token and the join policy live outside the file. A reviewer sees one connector entry that names a channel. Slack and Microsoft Teams are live. Email is experimental, per project.
Read together, the four blocks answer the questions a reviewer brings to an agent: which one answers a mention, what it can reach when it does, and which of its calls stop for a person. On a Slack bot that took a week to get approved, that is the part worth keeping in git.
- Read the guide: Getting started with Kortix.
Questions that come up before the first edit
What people ask about a manifest they did not write.
- What is kortix.yaml?
- The manifest at the root of a project repository. It declares the agents and what each one may reach, plus the connectors, secret names, triggers and the policies that decide which connector calls need approval.
- How do I give a Slack agent access to a tool?
- Add the connector’s slug to
agents.<name>.connectorsinkortix.yaml. A list such as[github, linear]reaches those two,allreaches every connector the project declares, and an omittedconnectorsgrant reaches none. - Where do connector credentials go if not in kortix.yaml?
- Into a connector account you authorize in Kortix, or into a project secret. The manifest only names secrets under
env:and lists connectors underconnectors:, and it never holds a credential. - Can I review an agent change before it takes effect?
- Yes for session work, which lands through a change request a person merges, with validation blocking a bad file at the merge check. A dashboard or API edit commits to the default branch at once, so that path gets no diff.
- What does policy.default_mode risk do?
- It decides the calls that no policy rule matches. A read runs, and a write or destructive call waits for approval. The default is allow_all, so risk is a choice you make in the file.
Make the agent’s rules a diff a person can read.
Connect Slack, then read the four blocks before the first mention.
Approval gates you set · Self-host is free · 3,000+ apps in a click