A workspace rule is something every member's agent reads before it starts work. Some rules say how the work should be done. Others say what must never happen. This page explains the difference, how rules from the workspace, a repository and a person combine, which products load them, and how to write one that holds.
A rule is a short piece of plain language that Unlok puts in front of the model before every task in your workspace. It has a title, a body, a kind (instruction or policy), an enforced switch, and a list of the products it applies to. Rules live on the dashboard under Governance, then Rules and policies, and every member's agent picks them up within a minute of a change. Nothing to install, nothing to commit.
Rules and policies are workspace owned and part of the Team plan. A team has one set that applies to all of its members. The person who writes a rule is recorded, but the rule belongs to the workspace, so it stays when they leave and it applies to people who join later. A personal workspace has no rule list; the repository and personal files described below still work for everyone in Unlok Code.
Rules are read by the model, not executed by a program, with one exception described under typed policies. A well written rule is followed reliably; a vague or contradictory one is not. The guidance under writing a good rule is what makes the difference.
Every rule is one of two kinds. The kind says what the rule governs and how much weight the agent gives it.
| Instruction | Policy |
|---|---|
| How the work should be done. | What must never happen, or must always hold. |
| Style, habits, preferences. The way your team likes things. | Boundaries the workspace sets for everyone. Safety, data, money, scope. |
| Followed as guidance. A repository or a person can refine or override it. | Followed as a limit. Usually enforced, so nothing below the workspace can loosen it. |
| Explain before you change. Tests before done. Plain language, outcome first. | No secrets in code or chat. No destructive actions without approval. No purchases or sign ups. |
| Read after the policies, in the order you listed them. | Read first. Enforced policies come before everything else. |
| Never enforced by code. There is no program that checks whether an answer was plain enough. | Can carry a type that a product enforces in code, regardless of what the model decides. |
A quick test when you are not sure which to pick: if breaking the rule would be a mistake to fix, it is an instruction. If breaking it would be an incident to report, it is a policy.
Title: Explain before you change Kind: instruction Before editing files, say in two lines what you will change and why. If the change touches more than three files, list them first and wait for a go ahead.
Title: No secrets in code or chat Kind: policy, enforced Never paste, commit, log or print API keys, tokens, passwords, private keys or customer data. Read secrets from environment variables and say when one is needed.
Enforced is a separate switch from kind, on purpose. It answers one question: can anything below the workspace override this rule?
An enforced rule sits above every other tier. A repository's own rules cannot relax it, a person's own rules cannot relax it, and the model reads it before anything else in the prompt. Most policies are enforced, because a boundary that a repository can switch off is not a boundary.
You can also leave a policy unenforced, as a strong default that a repository may relax with a rule of the same title, or enforce an instruction you never want overridden, like “always run the tests”. The two switches together give four combinations:
| Combination | Use it for |
|---|---|
| Instruction, not enforced | Team style that a repository or a person may adapt. The common case. |
| Instruction, enforced | A working habit the workspace requires everywhere, such as running tests before reporting done. |
| Policy, not enforced | A strong default boundary that a specific repository may relax with a good reason. |
| Policy, enforced | A boundary nothing below the workspace may loosen. Secrets, destructive actions, data handling. |
Rules come from three places, and the extension reads all three. From lowest to highest precedence:
| Tier | Where it lives |
|---|---|
| Workspace | The dashboard, Governance then Rules and policies. Applies to every member. |
| Repository | UNLOK.md at the root: the text above the first heading describes the repository, and every ## section is one rule named by its heading. A git ignored UNLOK.local.md beside it holds rules for this machine only. |
| Personal | ~/.unlok/UNLOK.md on each machine. Yours alone, in every repository you open. |
| Workspace, enforced | Above all three. Nothing below can override it. |
When two rules share a title, the higher tier wins and the lower one is dropped. The extension reports every such override under Settings, then Rules, so you can see that your repository's “Commit style” replaced the workspace's, or that the workspace's enforced “No prod keys” replaced a repository's attempt to relax it.
Rules with different titles do not conflict; they all apply. Keep titles specific so two rules about the same subject share one, and two rules about different subjects do not.
Each rule lists the products it applies to. A rule about browsing does not belong in a coding task's prompt, and a rule about commit messages means nothing to the Browser Agent. Untick the products a rule is not for, and only the ones you leave ticked load it.
| Product | How it loads rules |
|---|---|
| Unlok Code | Every task in the VS Code extension. Merges workspace rules with the repository's and your personal ones, enforced first. |
| Browser Agent | Unlok adds the rules marked for the Browser Agent to every task it runs on a team account, at the task's first request. |
| Optimus | Read once when Optimus builds its digest of the team's memory, and reused for every question until the digest refreshes, in every product that asks Optimus. |
| Chat | Unlok adds the rules marked for Chat to every conversation on the dashboard, at its first message. |
| API | Requests made straight to the API with a team key get the rules marked for API added by Unlok, unless the caller loaded rules itself and said so. |
A rule that applies to nothing is not allowed; the tab keeps at least one product ticked. See how rules reach the model for when each product reads them.
The tab ships with sixteen templates, filterable by product. Open one to read the full rule and a plain account of what it does on each product, then add it. A template becomes the workspace's own rule the moment it is added: rename it, change the wording, change where it applies, or remove it later. Nothing from a template loads until someone adds it and saves.
| Template | Kind |
|---|---|
| Explain before you change | Instruction, Unlok Code |
| Tests before done | Instruction, Unlok Code |
| Match the codebase | Instruction, Unlok Code and Optimus |
| Small commits, plain messages | Instruction, Unlok Code |
| Plain language, outcome first | Instruction, every product |
| Ask when a request can be read two ways | Instruction, every product |
| Say where an answer comes from | Instruction, Optimus |
| Report what was done on each site | Instruction, Browser Agent |
| No secrets in code or chat | Policy, enforced, every product |
| No destructive actions without approval | Policy, enforced, Unlok Code |
| Stay inside the open folder | Policy, enforced, Unlok Code |
| Customer data goes only to configured providers | Policy, enforced, every product |
| Prefer the cheaper model for routine work | Policy, Unlok Code and Optimus |
| No purchases, payments or sign ups | Policy, enforced, Browser Agent |
| Only the sites named in the task | Policy, enforced, Browser Agent |
| Team facts are not guessed | Policy, enforced, Optimus |
The model follows what it can act on. These habits make the difference between a rule that holds and one that gets ignored halfway through a long task.
| Do | Because |
|---|---|
| One behaviour per rule. | A rule that says three things gets two of them followed. Split it and each one holds. |
| Say the why in one clause. | "Never force push, because other people's branches build on main" is followed in cases the rule did not list. "Never force push" is followed only in the cases it did. |
| Name the action, not the attitude. | "Run the test suite before reporting done" can be checked. "Be careful with tests" cannot. |
| Say what to do instead. | A policy that only forbids leaves the agent stuck. "Stop at the review step and ask" gives it the next move. |
| Keep it under six lines. | Every rule rides along on every task. Long rules cost tokens on every step and get skimmed. |
| Use the same title for the same subject everywhere. | That is how a repository refines a workspace rule instead of contradicting it. |
| Pick policy for boundaries, instruction for preferences. | The agent reads policies first and treats them as limits. Putting a boundary in an instruction makes it negotiable. |
| Tick only the products the rule is for. | A browsing rule in a coding prompt is noise, and noise dilutes the rules that matter there. |
Avoid rules that contradict each other or the product's own behaviour. “Never ask questions” next to “Ask when a request can be read two ways” leaves the model guessing which one you meant, and it will pick differently on different days.
A repository carries its own rules in one file, UNLOK.md at the root, committed with the code so every clone gets them. Unlok Code offers to create it the first time you start a task in a folder without one, or type /init yourself. The agent then reads the repository and drafts the file, through the usual file approval.
--- workspace: 3f2a… # the team this repository belongs to; the switch card uses it workspace_name: Acme --- # Unlok Backend A FastAPI proxy in front of several model providers, billed per workspace. ## Tests before done Run the test suite before reporting a task complete. Show failures, don't describe them. ## Commit style One change per commit, message says what and why.
The text above the first ## heading describes the repository. Every ## section is one rule, named by its heading; that name is what a workspace rule of the same title refines or, if enforced, replaces. The front matter is optional: without it the file simply has no workspace binding.
UNLOK.local.md next to it is git ignored and holds rules for this machine only, in the same shape. Personal rules go in ~/.unlok/UNLOK.md and apply in every repository you open on that machine. Both rank above the repository and the workspace, but never above an enforced workspace rule.
This one file is the whole repository tier. If a repository still has the older .unlok folder, /init folds it into UNLOK.md and removes it. Workflows, hooks and skills live under .unlokrules, unchanged.
Reading is for every member of the workspace. Writing needs the Edit workspace rules grant, which owners and admins have by default and which an owner can give to other roles on the Members page. Everyone else sees the same tab read only.
Every save is one change to the whole set and is recorded in the workspace's audit log with who saved it, how many rules there were, and how many were enforced.
On a personal workspace the Rules and policies tab explains that the feature belongs to the Team plan and offers the upgrade. Your personal rules remain the file described above, which the extension reads on every machine it is on.
Rules are text the model reads, placed in the system prompt before the conversation. Three things decide when that happens, who does it, and how it is recorded.
| Question | Answer |
|---|---|
| When are they read? | Once, at the start: the first turn of a task in Unlok Code, the first request of a Browser Agent task, the first message of a chat conversation, the build of an Optimus digest. Not on every message. A running task keeps the rules it started with; the next one picks up any change. |
| Who puts them in front of the model? | Unlok Code does it itself, because it also merges the repository's and the person's files. Every other product gets them from the gateway: when a request arrives with a team key and no rules version, Unlok reads the workspace's rules for that product, renders them, and prepends them as a system message. The dashboard chat, the Browser Agent and scripts against the API need no code for this to hold. |
| Which rules? | Only the ones ticked for that product, in this order: enforced policies, then other policies, then instructions, each with its source. Unlok Code layers the repository's UNLOK.md and the person's files on top, resolving same-titled rules by tier. |
| How is it recorded? | Every rendered set has a version, a short hash of the rules in it. A product that loaded rules itself sends that version on each request; the gateway stamps the version it applied. The Requests page shows the version on every expanded request, and whether the caller or the gateway applied it, so a report that the agent ignored a policy can be checked against what was actually loaded. |
| What does it cost? | One read per session, then nothing. Products that poll for changes ask with the version they have and get a short not modified answer when nothing changed. |
Rules are rendered into one block near the end of the system prompt. Enforced rules first, then the rest, each with the tier it came from so the model can weigh them. This is what a task in Unlok Code reads when the workspace has one enforced policy and a repository has one instruction:
# Unlok Rules Rules from the workspace, this repository and the person, highest precedence first. An enforced workspace rule may not be overridden by anything below it. ## No secrets in code or chat (workspace rule, enforced) Never paste, commit, log or print API keys, tokens, passwords, private keys or customer data. Read secrets from environment variables and say when one is needed. ## Testing (repository rule) Run bun test before reporting a task done.
A change on the dashboard reaches the next task, conversation or Optimus digest, not the ones already running. Every request records which version of the rules it ran under, so a “the agent ignored the policy” report can be checked against what was actually loaded.
A script or a service that calls Unlok with a team key follows the workspace's rules too. Two headers and one endpoint cover every case, and the default needs no code at all.
| You want to | Do this |
|---|---|
| Let Unlok apply the rules | Nothing. A completion from a team key that carries no rules version gets the rules marked for API prepended as a system message. Send a session id with your requests and the read happens once, at the first message, instead of once a minute. |
| Say which product you are | Send X-Unlok-Surface with chat, browser, optimus, extension or api. Unlok applies that product's rules. A missing or unknown value counts as API. |
| Load the rules yourself | GET /v1/rules?surface=api with your key returns the rules that apply, a rendered block ready for a system prompt, and a version. Put the block in your own prompt, then send X-Unlok-Rules-Version with that version on each completion. The gateway leaves your prompt alone and the Requests page records the version you loaded. |
| Poll cheaply | The version travels as an ETag. Send it back in If-None-Match and unchanged rules answer 304 with no body. |
| List the products | GET /v1/rules/surfaces returns the registry the dashboard's product chips come from, so a new product never needs a hard coded list. |
| Use a personal key | GET /v1/rules answers available: false with the reason team_plan, and nothing is prepended to completions. |
# The rules marked for API, with their version as an ETagcurl -i "https://unlok-backend-xpts.onrender.com/v1/rules?surface=api" \ -H "Authorization: Bearer $UNLOK_API_KEY" # Ask again later with the version you have; 304 means nothing changedcurl -i "https://unlok-backend-xpts.onrender.com/v1/rules?surface=api" \ -H "Authorization: Bearer $UNLOK_API_KEY" \ -H 'If-None-Match: "a1b2c3d4e5f6"' # Your completion carries the block in its own prompt, so the gateway adds nothingcurl https://unlok-backend-xpts.onrender.com/v1/chat/completions \ -H "Authorization: Bearer $UNLOK_API_KEY" \ -H "X-Unlok-Rules-Version: a1b2c3d4e5f6" \ -H "Content-Type: application/json" \ -d '{"model": "auto", "messages": [...]}'
The response body has version, workspace (type, id and name), surface, rules (id, kind, title, body, enforced, applies to) and rendered, the same block the gateway would have prepended. Rules for other products are one query away: surface=browser for an automation that drives a browser, surface=chat for a chat front end.
Text tells the model. Code stops the action. A typed policy is a policy with a small configuration that a product enforces itself, whatever the model decides. The text still reaches the model, with one sentence added saying what is enforced, so a product that cannot enforce the type at least tells the model. Pick the type under Enforced in code in a policy's editor, or start from a template that has one.
| Policy type | What happens |
|---|---|
| Allowed domains | Only the sites you list may be opened, each with its subdomains. The Browser Agent blocks any other address before it loads and names the policy; an enforced policy replaces the local firewall list, a plain one adds to it. Unlok Code's web fetch tool refuses the address, and the model is told why. |
| Blocked actions | A click that would buy or check out, pay, sign up or create an account, send or submit, or delete is refused by the Browser Agent instead of being sent for approval. The task reports what remains for the person. |
| Spend cap per task | Unlok adds up what a conversation costs, vendor price, routing and fee, and refuses its next request once it has reached the cap, with an error that names the policy. Every product at once, since the gateway does it. A request Unlok cannot tie to a conversation is not capped. |
| Model allowlist | Unlok routes only to the models you list, as provider/model. A request that pins any other model is refused, auto routing skips models outside the list, and a tier with nothing allowed is refused up front. Every product at once. |
What the person sees: the policy's row carries the type, the Browser Agent's Options page lists what it enforces, and a refusal reads like “Blocked by the workspace policy ‘No purchases’: this Browser Agent may not buy or check out.” Two policies of the same type combine: their lists are joined and the lower cap wins.
| Term | Meaning |
|---|---|
| Rule | Any entry on the Rules and policies tab. An instruction or a policy. |
| Instruction | How the work should be done. Guidance a lower tier may refine. |
| Policy | What must never happen, or must always hold. A limit, read first. |
| Enforced | Cannot be overridden by a repository or a person. Sits above every tier. |
| Applies to | The products that load the rule: Unlok Code, Browser Agent, Optimus, Chat, API. |
| Tier | Where a rule came from: workspace, repository, personal, or workspace enforced. |
| Override | A higher tier rule with the same title replacing a lower one. Reported in Settings, then Rules. |
| Template | A starting point on the tab. Becomes your own rule once added. |
/init | Creates UNLOK.md at the repository root, bound to the active team, then drafts it. |
| Version | A short hash of a rendered set of rules. Recorded on every request, shown on the Requests page. |
| Gateway | Unlok adding the workspace's rules to a request whose caller did not load them itself. |
| Typed policy | A policy with a configuration a product enforces in code: allowed domains, blocked actions, spend cap per task, model allowlist. |
X-Unlok-Surface | Header naming the product a request is for, so the gateway applies that product's rules. |
X-Unlok-Rules-Version | Header a caller sends when it loaded the rules itself. The gateway then adds nothing. |
The operational layer between your team and every AI model it touches.