What you will have
A roster agent called Underwriting Agent. When an application ticket is assigned to it in Linear, it pulls the Middesk result, the registry and ownership records, and the application answers from a read-only database, checks each provider flag against the underwriting policy in Notion, and writes a decision memo in which every flag is either resolved with a source or listed as open. If a document is missing it drafts the request. Every Monday it re-reviews merchants due for a periodic check and posts the summary to Slack. It cannot change an application’s status, write to the database, or send anything to a merchant; those wait for an underwriter. This page follows the six steps of Build an agent. The Build pages explain each step; this page gives the concrete values for this one agent.The agent spec
1. Define the job
Read Define the job first. The objective needs an input, an output and a boundary; underwriting has an unusually sharp boundary, so write it down before anything else.Create the roster agent
Underwriting Agent. On Instructions, use this description:Given a pending merchant application, compares the KYB provider result, the business registry, beneficial ownership and the application answers, and writes a decision memo where every flag is resolved with a source or listed as open, plus a draft document request. Never changes an application’s status.And these system instructions:
Point it at a template
Underwriting (create it in step 3 if it does not exist yet) and leave Coding agent on Claude Code. Click Save profile.2. Measure success
Read Measure success. Underwriting has three kinds of run and a grader can only judge one category at a time, so give it three.
Three categories, each with a when-to-use, a success criterion and the human cost that prices the scorecard.
Add the three categories
risk_tier on every category with the instruction “low, medium or high, taken from the memo’s recommendation line”. Set Avg human cost (USD) to 90 and Avg human time (minutes) to 75.Set the monthly budget
800. This flags the agent on the scorecard and writes an audit event when spend passes the cap. It does not stop runs; use org limits under Guardrails > Limits for a hard cap.rubric.json for the CLI:
3. Give it tools
Read Give it tools. None of the KYB vendors is a built-in provider, so Middesk is a custom provider here; Persona or Alloy would be set up the same way with their own fields. Postgres is also custom. Notion is built in.
Tools and MCP servers are added from the same chooser. Middesk and Postgres are custom tool providers; Notion comes from the catalog.
Create the Underwriting template
Underwriting, and click Create Template. Nothing is cloned; the template exists to carry connections, the skill and later the guardrails.Define Middesk as a custom provider
MIDDESK_API_KEY; an optional base URL lets you point the sandbox at Middesk’s sandbox environment while proving.Connect Middesk at agent scope
Underwriting Agent. An agent-scoped connection is used only by this agent’s runs, so Middesk usage is attributed to the agent, and it reaches the agent’s sessions without any skill having to require it. The CLI creates only org and personal connections, so this one is done in the dashboard. See the credential hierarchy.Define and connect Postgres read-only
postgres, with one static field connection_string (kind secret) materialized to POSTGRES_CONNECTION_STRING. Connect it at org scope with a role that can only SELECT from the applications, owners and documents views. Nothing in Runtime downgrades a credential, so the read-only guarantee has to come from the database role.Connect Notion from the catalog
requires.integrations. The skill in the next step names middesk, postgres and notion, so Postgres and Notion arrive through the skill and Middesk arrives both ways.
4. Define how it works
Read Define how it works. The runbook is a skill, the prohibitions live in the instructions and the skill for now, and the triggers are Linear plus a schedule. Guardrails wait until step 6.Write the underwriting-memo skill
SKILL.md is the procedure:references/memo-template.md, excerpt:references/flag-glossary.md maps each Middesk task key (for example tin, address_verification, sos_active, watchlist) to what it means and which policy section governs it.Create the skill, upload the two reference files, and declare the providers it requires.Attach the skill and build the template
underwriting-memo to the Underwriting template and build once. Anything attached after this build is not in the snapshot until the next one.Connect Linear for new applications
Underwriting, and under Team overrides route the Underwriting Linear team to this template so that other teams’ assignments do not launch it. Assigning a ticket to the agent, or mentioning it, launches a run; the memo comes back as agent activities and a comment on the issue.
Triggers connect from the agent sheet. Linear finishes in the browser; Email is one click.
Schedule the periodic reviews
Periodic merchant reviews, run it as the Underwriting Agent roster agent so the run is graded under periodic-review and receives the agent-scoped Middesk key, and use this prompt:
Run the periodic review for every merchant whose next_review_at is before today. One memo per merchant using the underwriting-memo skill. End with a summary table: merchant, risk tier, what changed.
Schedule it weekly on Monday at 13:00 UTC and post to the #underwriting Slack channel. Cron is five fields in UTC with no time zone, so 13:00 UTC is 06:00 in San Francisco in summer and 05:00 in winter. Create it disabled; you enable it in step 5 after a Run now.5. Prove it works
Read Prove it works and iterate. No guardrail exists yet on purpose. The agent is safe by scope: the database role is read-only, Middesk is called with a key you can point at its sandbox environment, the sandbox is destroyed after each run, and the Linear team is a test team or the schedule is disabled.Seed five applications
Run the Linear cases
memo_attach approval, the session card shows Approve and Reject; approve to let it finish so it can be graded.
A run waiting on an approval shows it on the session card; approve to let the run finish and be graded.
Run the schedule once by hand
Periodic merchant reviews. It executes the identical code path a Monday tick takes, so a misconfigured schedule fails in front of you instead of silently at 13:00 UTC. Read the summary in #underwriting.Read the grades and the scorecard
Underwriting Agent: six graded runs, the hit rate, and value returned at $90 per success.Tighten one thing, re-run, then enable the schedule
success_criteria. A run that could not read documents gets the view added to the role. Change one thing, re-run the affected case, and only when all five pass enable the schedule.While the cases run, write down every command pattern and host the agent used. That list is the input to step 6.6. Add guardrails and approvals
Read Add guardrails and approvals. Only now, with five passing cases, do you know what the agent runs. Add one rule at a time and re-run a seeded case after each.Deny writes to the application tables
psql, then attach them to the Underwriting template.Deny Middesk writes, except the one the runbook needs
POST to /v1/businesses. Ordering extra verifications is a POST under /v1/businesses/<id>/. Deny beats allow whenever both match, so the deny pattern itself has to leave out any path you intend to keep.If onboarding already created the Middesk business and the runbook only reads, deny every POST:If the runbook must create the business itself, deny only writes below an existing business plus every PATCH and DELETE. The create call matches no deny rule and falls through to the allow rule, so it needs no rule of its own:Set the default policy to ask
ask, so any command outside the patterns above pauses for a permission decision instead of running. The CLI does not set this; use the tab or PUT /api/cloud/organizations/<org_id>/allowlist-policy with {"default_policy": "ask"}.Pin the network
Rebuild and re-run a case
Keep both approval gates in the runbook
memo_attach before the memo is posted to the ticket, and document_request before any request goes to the merchant. Both use --required-team <underwriting_team_id> so only underwriters can resolve them; admins and owners always can. Approvals are resolved on the session card or with the CLI, not in Slack or Linear.What stays human
- The decision. The memo ends in a recommendation; an underwriter approves, declines or conditions the application in the application system. The agent has no path to that status field: the database role cannot write, and the deny rules refuse the attempt.
- Anything sent to the merchant. The agent drafts the document request; a person sends it after the
document_requestapproval. - Ordering new verifications. Unless you deliberately allow the single create-business path, the agent reads what onboarding already ordered.
- Changing the rubric. When the grader disagrees with an underwriter, the underwriter edits the success criteria, not the agent.
Gotchas
- Middesk is not built in. It is a custom provider you define; the JSON above is the whole definition. Persona and Alloy are set up the same way with their own field names and base URLs.
- The agent-scoped Middesk key applies only to this agent’s runs. A session someone opens from the
Underwritingtemplate by hand does not receive it, and falls to a personal or org-wide Middesk connection if one exists, otherwisemiddeskshows as an unmet requirement. - Postgres and Notion arrive through the skill. If
requires.integrationsonunderwriting-memodoes not listpostgresandnotion, those org-wide connections are silently left out of the session. - Attached is not built. After attaching the skill or a rule,
template getshowsattachments_changed_since_build: trueuntil you build again. - Schedules run in UTC.
0 13 * * 1is Monday 13:00 UTC all year; local time shifts with daylight saving. - A periodic run with no post target is silent. Set the Slack channel on the schedule or the summary is only visible under Sessions.
- Deny beats allow. A deny pattern such as
curl*-X POST*api.middesk.com*also matches the create-business call, and no allow rule can rescue it. If the runbook creates the business, narrow the deny toapi.middesk.com/v1/businesses/*so the create path never matches a deny rule. - Approvals with nobody watching wait forever. Scope
--required-teamto the team that is on rotation, and give the runbook await --timeoutso a run fails cleanly at end of day instead of idling.