# Rekan.Ai Workload Packs

A workload pack is the declarative template for one business-function agent box. It answers a single question: if a customer says "give me a finance coworker", what box do we ship? The pack fixes the persona, the business tools the box may call, the actions a human must approve, the skills preloaded into the box, and the resource envelope it is deployed with.

Packs live in control-plane/rekan/catalog/workloads/ — one YAML file per pack, filename stem equal to the pack slug. Nothing in a pack is a secret; see Secrets below.

  • Catalog: control-plane/rekan/catalog/workloads/
  • Deploy-time box config (not this repo): /etc/rekan/box.yaml + /etc/rekan/box.env
  • Applied on the box by: rekan-box-apply

# The catalogue

slugnameverticalgatewayskillsnotable guardrails
generalGeneral Coworkergeneraltelegram3no privileged tools at all: shell.exec, ssh.connect, secrets.read forbidden; external sends need approval
finance-cfoFinance Copilotfinanceslack4read-only on money: ledger.write, bank.transfer forbidden, payments.create / journal.post / price.update gated; financial data class
finance-accountingAccounting Clerkfinanceemail4bank.transfer + ledger.delete forbidden; journal.post, invoice.approve, tax.filing.submit gated; closed-period posts refused
supplychain-logisticsLogistics Coordinatorsupplychaintelegram4customs.declare forbidden; shipment.reroute, carrier.book, freight.cost_approve gated
supplychain-procurementProcurement Officersupplychainemail4vendor.bank_detail_change forbidden; po.commit, vendor.onboard, contract.sign, price.update gated
legal-counselLegal Counsel Aidelegalteams4legal_privileged data class; privilege.waive forbidden; contract.sign, nda.execute, legal.filing.submit, advice.finalize gated
hr-people-opsPeople Ops Coordinatorhrslack4pii class, pii.export forbidden; offer.send, employee.terminate, payroll.adjust gated
sales-revenue-opsRevenue Ops Copilotsalestelegram4forecast.publish_external forbidden; quote.send, discount.approve, contract.sign, crm.bulk_update gated
customer-supportSupport Desk Agentsupportlark3customer.record_delete forbidden; refund.issue, account.credit, data.subject_erasure gated
engineering-devopsPlatform Engineerengineeringdiscord4only pack with terminal; shell.exec_root, secrets.read_plaintext, db.drop, publish.public_release forbidden; deploy.production, infra.destroy, iam.grant gated
marketing-growthGrowth Marketermarketinglark4brand.impersonate forbidden; campaign.launch, publish.public, social.post_external, budget.adjust gated
data-analystData Analystdataslack4prod.write forbidden, writes only to scratch; dashboard.publish_public, data.export_external, pii.unmask gated

Reading the table: skills is the count of preloaded Hermes skills, not capabilities. Approval-gated actions are the ones that stop and ask a human; forbidden actions are refused outright regardless of who asks.

# How to add a new pack

  1. Copy the closest existing pack as a starting point: cp control-plane/rekan/catalog/workloads/data-analyst.yaml .../catalog/workloads/<slug>.yaml
  2. Set slug to exactly the filename stem. The loader keys on the stem and will reject a mismatch.
  3. Fill every field described below. Keep the pack differentiated — a new vertical is defined by its capabilities, its guardrails and its skills, not by a renamed copy of an existing pack.
  4. Validate before committing:

``bash python3 -c "import yaml,glob;[yaml.safe_load(open(f)) for f in glob.glob('control-plane/rekan/catalog/workloads/*.yaml')]" \ && grep -rnE 'sk-[A-Za-z0-9]{8,}|api_key: [A-Za-z0-9]' control-plane/rekan/catalog/workloads/ ; ls -1 control-plane/rekan/catalog/workloads/*.yaml | wc -l ``

  1. Add a row to the table above and open a PR.

# Schema, field by field

Every pack has exactly these top-level keys.

fieldtyperules
slugstrMust equal the filename stem. Lowercase, hyphenated, family-detail (finance-accounting) or bare family (general).
namestrHuman label shown in the catalog and the box's SOUL.md, e.g. Finance Copilot.
verticalstrFamily key shared by related packs (finance, supplychain, legal, hr, sales, support, engineering, marketing, data, general). Drives grouping in the UI.
taglinestrOne line of business value, ≤90 characters. No trailing period needed. Goes in the catalog card.
summarystr2–4 sentences: what the box does day to day, written for a buyer, not for an engineer.
persona.rolestrThe job title the box plays (Chief Financial Officer analyst). Becomes part of the box identity.
persona.languagestrWorking language. id unless the vertical is inherently English (legal-international, etc.).
persona.tonestrHow it sounds. One clause, not a personality essay.
persona.directiveslist[str]3–6 short imperatives that change behaviour. This is where domain judgment lives — cite the source, state the currency, escalate churn risk. If a directive could apply to any agent, cut it.
capabilitieslist[str]Dotted business-tool names the box may call: knowledge.search, sheets.read, docs.write, email.draft, erp.read, ledger.read, contract.clause_extract, po.draft, shipment.track, invoice.extract, ticket.update, crm.read, calendar.propose, … Use read/write/draft suffixes; a draft capability never commits.
guardrails.human_approval_requiredlist[str]Dotted actions that must be approved by a human before executing. Every irreversible or money-moving action belongs here — payments.create, contract.sign, po.commit, journal.post, price.update, message.send_external, deploy.production, refund.issue. An action must not appear here and in forbidden.
guardrails.forbiddenlist[str]3–6 dotted actions or behaviours the box must never do, regardless of approval: shell.exec, ssh.connect, secrets.read, publish.public, data.export_bulk, bank.transfer, priv.waive.
guardrails.data_classeslist[str]Subset of public, internal, confidential, pii, financial, legal_privileged. Declares the highest classification the box handles; the deploy tool uses it to pick egress and logging policy.
guardrails.egress_allowlist[str]host:port the box may reach — internal systems it needs plus its gateway host. The model endpoint goes in as the literal token model-endpoint, which the control plane expands to the configured REKAN_MODEL_BASE_URL host:port at render time; never hardcode an address here or the pack breaks the moment the deployment moves. Default-deny: anything not listed is blocked.
skillslist[str]Hermes skill slugs preloaded into the box. Match the workload: numbers-heavy → xlsx/powerpoint; document-heavy → pdf/docx/grounded-citations; comms-heavy → email-inbox-triage/meeting-action-items.
toolsetslist[str]Subset of web, terminal, files, browser, memory, cron, delegation, vision, tts. Keep narrow. terminal is never granted to finance, legal, hr or support packs.
model.provider / api_key_envstrInference target. provider: custom, api_key_env: NETRARUNTIME_API_KEY. The endpoint and the model name are deployment settings, not pack data (REKAN_MODEL_BASE_URL, REKAN_MODEL_DEFAULT) — a pack that pins base_url/default ships a box that cannot reach its model when the deployment moves, and tests/test_control_plane.py fails it. api_key_env names a variable only — never a value.
resources.cpuint2–4 vCPU. 2 for coordination-heavy boxes, 4 for spreadsheet/document/data work.
resources.memorystrGiB string, "4GiB" or "8GiB".
resources.diskstrGiB string, "20GiB" or "40GiB".
gateway.platformstrExactly one of telegram, slack, lark, discord, teams, email — where the coworker talks to its owner.
gateway.enabledbooltrue for shipped packs. false keeps the box headless (cron/API only).
versionintSchema/pack version, currently 1. Bump only when the pack's meaning changes in a way that alters an already-deployed box.

# Secrets

Packs are secret-free by construction. No token, password, API key or credential of any kind is written into a pack. At deploy time the operator places credentials in /etc/rekan/box.env (mode 0600) on the box itself, and rekan-box-apply installs them into the Hermes home as .env. Packs reference credentials only by variable name via api_key_env.

CI enforces this with a blocking grep for secret-shaped literals (sk-…, xox…, ghp_…, AKIA…, token=, long base64 blobs) across the catalog.

# Container safety checklist

A pack is only mergeable if all of these hold:

  • parses with yaml.safe_load and carries every top-level key above;
  • slug equals the filename stem, tagline ≤90 chars;
  • toolsets never contains terminal for a finance, legal, hr or support pack;
  • every irreversible or money-moving capability appears in human_approval_required;
  • no action appears in both human_approval_required and forbidden;
  • forbidden has 3–6 entries and includes the relevant subset of shell.exec, ssh.connect, secrets.read, data.export_bulk, publish.public;
  • no literal secret anywhere in the file.

# From pack to running box

catalog/workloads/<slug>.yaml     declarative template (this doc)
        │  deploy tool renders it, merges operator inputs
        ▼
/etc/rekan/box.yaml               per-box non-secret config (name, role, owner, gateway)
/etc/rekan/box.env                per-box secrets, 0600, written by the operator
        │  rekan-box-apply (first boot + on demand, idempotent)
        ▼
~/.hermes/config.yaml + SOUL.md   live Hermes box, gateway service installed

rekan-box-apply is idempotent: re-running it on a live box rotates a key or renames the coworker without a rebuild. Config mutations go through hermes config set, never by hand-editing config.yaml.