Business . Technology . Strategy

How I Manage a Self-Building, Self-Sustaining Trading Platform with AI Agents
AGENTIC WORKFLOW · CLAUDE CODE · AI AGENTS

How I Manage a Self-Building, Self-Sustaining Trading Platform with AI Agents

SAT OCT 24 2026◆22 MIN READ◆NORIK DAVTIAN

AI agents run most of the engineering work on Matador, a live options-trading platform. A mistake here ripples outward in milliseconds: a bad fill, then a red candle you could see from orbit, then real dollars gone before the stack trace finishes printing. One bad line, tsunami.

Every day, without me:

  • they groom the backlog and start the work that is ready;
  • they read production logs and surface anything new;
  • they repair the market-data feed before I know it broke;
  • they patch security advisories the morning they land.

They have never touched the six files that could cost me money. That sentence is the whole article: getting agents to do work is easy, getting them to never destroy anything is the job. Below are the rules and the templates.

Value first. Paste this into your coding agent now. You will have a plan for your repo by the time you finish reading:

Read this article:
https://norik.io/posts/ai-agents-trading-platform

Then read my repo and give me a plan to automate a
TPM for it. Be specific to what you find here:

1. What my north star doc should say, and where
   it lives.
2. Which labels my issue tracker needs, what each
   one means, and which issues are mislabelled now.
3. Which files belong on the protected list - the
   ones where a bad change costs money or data -
   and why each one.
4. What "verified" means in this repo, as the exact
   commands (typecheck, lint, build, tests).
5. Which of my recurring production errors belong
   in a known-error catalog, and what each one is.
6. What should run daily, weekly and monthly.

Then write the skill file and the memory index,
filled in for this project. Change no code.
Open no pull requests. Show me the plan first,
and ask me questions wherever you need a
decision from me rather than guessing.

The AI Product Manager Is a File in the Repo

Your product manager should be a file, not a chat window. Mine is markdown in the repo, versioned beside the code it manages and reviewable in a pull request. Its modes: daily, groom, prioritize, critical-path, dispatch, deps, security.

Rule one: three sources of truth, and they never overlap.

  • North star doc — direction, in stages with exit criteria. The agent proposes edits. I ratify them.
  • Issues and milestones — the only place status lives. Milestones are the north-star stages.
  • Plan docs and changelogs — reasoning and history. Never status.

That third line kills a class of drift. A roadmap file that says “in progress” is a lie within a week. An issue that says it is a fact you can query.

Rule two: every run starts from the same read-only snapshot. Issues, PRs, branches, commits, the dependency audit. Same shape every morning, so no two runs disagree about what is true.

Rule three: read code from origin/main, never the working tree. My checkout is usually twenty commits behind and shared with other sessions. A citation from a stale tree is a hallucination with a line number on it — the most convincing kind.

Copy it. Every project-specific fact sits in one table at the top; nothing below it changes between repos.

---
name: project-manager
description: >
  Technical program manager for this repo. Owns
  the north star and keeps every open issue, plan
  doc and maintenance chore in order behind it.
  Use for: what to work on next, the backlog,
  priorities, grooming, the critical path,
  milestones, planning, starting work on an issue,
  outdated packages, security, or project status.
argument-hint: "[daily|groom|prioritize|dispatch]"
---

# Project Manager

## Project facts

Fill these in. Nothing else below is
project-specific.

north_star:      docs/NORTH_STAR.md
approver:        <name>
protected_files: <path>, <path>, ...
verify_with:     <typecheck> <lint> <build> <test>
worktree_root:   .claude/worktrees/
agent_cap:       2

## Sources of truth

- **North star doc** - where the project is
  going, in stages with exit criteria. You
  propose edits; the approver ratifies.
- **Issues + milestones** - the ONLY place that
  carries status. Milestones are the stages.
  Label, comment, set milestones, and close
  *with evidence*.
- **Plan docs, changelogs** - reasoning and
  history, never status.

## Modes

daily (default) - groom - prioritize
critical-path - dispatch [#n] - deps - security

Every mode starts from one read-only snapshot:
issues, PRs, branches, commits, the dependency
audit. So every run reasons from the same
evidence. Read code state from origin/main in its
own worktree, never the working tree - a citation
from a stale checkout is a hallucination with a
line number on it.

## Grooming

- Every open issue is either actionable or a
  decision. Actionable means a What, a `## Do`,
  and enough file references to start in ten
  minutes.
- Close by evidence, never by vibe. Cite the
  merged commit as the closing comment.
- Never close a `decision`. Make deciding cheap
  instead: options, a recommendation, what it
  blocks, what happens by default.
- Do not churn. Relabel when a label is wrong,
  not when it is merely imperfect.
- Dead citations are bugs: a reference to code
  that moved sends the next reader on a detour.

## Prioritizing

Hard gates first - safety, live security
exposure. Then north-star contribution, blast
radius and evidence of pain, discounted by
effort. Output a ranked Next 10, one line of
"why here" each.

Stability beats precision: move an item only when
a FACT changed - a decision landed, an incident
happened, a prerequisite shipped - and name the
fact beside the move.

## Dispatch

Eligible = P0/P1 and none of:
  - no `## Do` section
  - names a protected file
  - asks for a plan or a design
  - open blockers in its `Blocked by:` line
  - already referenced by an open PR or branch
  - labelled decision, blocked, or in-progress

Print two lists - "launch now" and "not
dispatched, and why" - and put the second in the
report verbatim. Never widen eligibility by
judgment: if a rule is wrong, change the rule, in
a PR, where someone can review it.

## Guardrails - read before acting

These exist because each one has already cost
real work or real money.

- Protected files are absolute. You never edit
  them, no agent you launch edits them, and an
  issue naming one goes to *Needs you* for a
  per-file OK. Write this rule in three places:
  the agent-instructions file, this skill, and
  the dispatch script. An instruction in one
  place is a suggestion.
- You open PRs; the approver merges. Never merge,
  never push to the default branch, never delete
  a branch - report merged ones as a list.
- Never touch the shared checkout. No checkout,
  switch, stash or reset: other sessions are
  using it. Work happens in a fresh worktree.
- No production writes. You read the repo and
  the issue tracker.
- Surgical edits only: labels, milestones,
  `Blocked by:`, a `## Do` section, checklist
  ticks, comments. Never rewrite anyone's prose.
- Read-only when unsure. If the snapshot fails or
  the tracking issue looks hand-edited in a way
  you do not understand, report and stop.
- First-run gate. Creating milestones,
  relabelling dozens of issues and launching
  agents are a lot of outward-facing change:
  present the plan and get a yes. Security
  patches are the one exception - the patch is
  the point.

## Report

*Needs you* first - decisions, approvals, agents
that returned without a PR. Then the critical
path, what you did, maintenance, the watch list.
Keep it short; the tracking issue is the long
form.

End every run with one status line, always the
same shape, so a month of them reads as a trend:

PM <date>: <open> open - P0 <n> - P1 <n>
decisions <n> - audit C<n>/H<n>
agents <running>/<cap> - needs you: <n>

GitHub Issues as the Only Source of Status

If one place holds status, it has to be machine-readable. GitHub drops this repo’s issue types silently, so labels carry every classification — and the set stays small enough that each one has a job.

P0  Capital safety or live security exposure
    - before anything else
P1  Reliability, or a blocker on the path to
    the next stage

decision     Not work - a call a human makes
backlog      An umbrella checklist, not an item
blocked      A "Blocked by:" line names an open
             issue
in-progress  An agent was dispatched; a comment
             names the branch

Declare dependencies, do not describe them. Somebody writes “after we land the transaction work” in a body; the groom turns it into a Blocked by: line. Now the critical path is the longest chain of those edges, and its head — the one item unblocked right now — is what to work on today. No meeting required.

Close by evidence, never by vibe. An issue closes when the agent can cite the commit that delivered it, posted as the closing comment. Never “this looks done.”

Never let the agent close a decision. Its job there is to make deciding cheap: the options, a recommendation, what it blocks, and what happens by default if nobody decides.

Dispatch Rules and Protected Files

A planner that only plans is a diary. A script computes eligibility and prints two lists: launch now, and not dispatched, and why. The second goes into the report verbatim, so every exclusion is visible.

An item is eligible only if it is P0 or P1 and none of these holds:

  • it is a decision, an umbrella, blocked, or already in flight;
  • it has no “Do” section — the agent would be guessing at scope, and writing that section is the TPM’s own work, so it dispatches tomorrow instead;
  • it asks for a plan, because a plan is a conversation and not a pull request;
  • a branch or open PR already references it — two agents on one issue is how you get competing branches nobody can merge.

Eligibility is never widened by judgment. If a rule is wrong, change the rule — in a pull request, where someone reviews it. An agent that can reason past its own eligibility check does not have one.

Six files are permanently off-limits: the coordinator that turns a signal into an intent, the worker that runs it, the client that routes live versus paper, live execution, paper execution, pricing. Change one badly and you get a fill.

The rule is written three times: in the agent-instructions file every coding agent reads on entry, in the TPM’s guardrails, and in the dispatch script as a mechanical exclusion that routes any issue naming one of those files to Needs you.

Three places, because an instruction in one place is a suggestion. The prose explains the boundary; the script makes crossing it impossible by accident at three in the morning. A seventh file joined later by incident — the set grows, it never shrinks quietly.

Production Error Triage Through an MCP

Production errors cost you twice: when they happen, and every morning somebody re-derives what they mean. Delete the second cost.

A daily sweep reads production logs through the BetterStack MCP. One column does the work: the store derives a pattern per line with dynamic parts stripped, so grouping by it collapses tens of thousands of near-identical lines into a handful of buckets. The agent reads fifteen buckets, biggest first, and labels each:

  • Benign noise — count it, move on.
  • Known and actionable — is it worse than baseline?
  • NEW — not in the catalog. Top of the report, with an example.
  • SPIKE — a known-benign pattern at abnormal volume. This is the one that catches real incidents.

A nominal day is one line. A daily report nobody can skim is a daily report nobody reads.

TRIAGE <date>: <total> patterns | <new> new | <spikes> spiking | <actionable> actionable

The sweep observes and proposes. It never acts. No pull requests, no pushes, no config changes. A recurring new pattern becomes a proposed catalog row, and it asks first. If the MCP is not attached it falls back to runtime logs and says so, instead of quietly reporting a narrower window as the whole history.

The catalog is the asset. Without it, triage re-derives the same conclusions every morning and gets them wrong about one morning in five. The row that saved me the most time describes an error-level alert that looks exactly like production — until you check the stack and find a path under a user’s home directory and a fixture account number. A local test run, shipping into the production log source, firing a real alert. Hand an agent that error with no catalog and it investigates for an hour, then writes a convincing postmortem of something that never happened.

Self-Healing Infrastructure: Four Steps to Recovery

An alert that means “a human must fix this” does not scale. Build the ladder, and the alert changes meaning.

What happened. The shared market-data socket went quiet ten minutes after the open. The price path noticed, forced a reconnect, and trading recovered. Quote capture never did: seven hours of staleness alarms while the day’s bars became a hole in the store.

Why. A forced reconnect builds a new feed object. The capture service had attached its listener once, guarded by a boolean nobody reset, so every tick re-added subscriptions to the new feed while the listener stayed bound to the dead one. Bars were flowing. Nobody was listening.

The fix is a ladder:

  • Rebind on replacement — a changed feed reference heals within one tick.
  • Re-arm subscriptions every tick, in paced groups — not because subscriptions vanish often, but because they vanish partly. Sent as one burst, a whole watchlist only partly lands, and an unpaced retry loses the same chunk every time.
  • Repair backfills driven by staleness — pulled through the one-shot bulk path, which attaches its own listener to the current feed and works even while the stream is broken.
  • Bounded auto-reconnect — triggered when two consecutive repairs of the lead symbol come back empty, floored by a cooldown. The feed is shared with live trading, so recovery must never become a reconnect storm.

The payoff is the alert. It used to mean a human needs to reconnect this. Now it says recovery is running — and a repeated alert means the ladder itself is failing, a rarer and more interesting page. The catalog row uses the same words, so the agent at 6am and the engineer at midnight reach the same conclusion.

The same shape turns up everywhere. The database pool’s error handler used to kill the process; now it logs and lets the pool re-establish. At the trading layer, plain-English rules watch open positions and act before a bad trade gets worse: trailing stops that tighten as price moves, daily loss limits, caps on time in a trade that is not working. Every adjustment is recorded with its reason. New rules start on paper.

Self-Upgrading Software: Daily, Weekly and Monthly Maintenance

Maintenance runs on a ledger, not on the weekday. A missed Monday still owes its weekly.

  • Daily — the dependency audit. A critical or high advisory with a non-major fix becomes a pull request today, without asking: typechecked, linted, built, tested. A vulnerability is not a decision; the patch is the point. Never fix one by jumping a major version.
  • Weekly — the bump batch, a groom, a re-prioritization, and a report of stale branches: a list, never a deletion.
  • Monthly — a fact-check pass over the two or three specs least recently touched. Scheduled maintenance for the documentation itself, and the most underrated line in the cadence.

New capability earns its way out of the shadows. Pre-trade advice ran as a dry run first: thousands of signals observed, every piece of advice it would have given recorded, nothing acted on. It graduates only after being right in the dark long enough to argue about. The exit logic shipped the same way.

The ceiling, everywhere: pull requests are opened, never merged. Autonomy ends where something becomes irreversible.

Stability beats precision. A priority order that reshuffles every morning teaches everyone to ignore it, so an item moves only when a fact changed — and the report names the fact next to the move. When the snapshot fails, or the tracking issue looks hand-edited in a way the agent does not understand, the run reports and stops.

The Documentation Layers, and What Each One Owns

One folder of equally-weighted markdown is where drift starts. Nothing in a file tells you whether it is a promise, a record or a leftover, so an agent reads a two-year-old plan as fact and builds on it.

Every document declares, in its first lines, what genre it is, how much authority it carries, and when it was last true.

What each layer owns

  • North star — direction only, in stages with exit criteria.
  • ARCHITECTURE.md — the map: layering, data flow, where business logic is allowed to live. First thing anyone reads.
  • Spec of record, one per subsystem, named after it — what is true right now.
  • pipeline/ — the plan of record: phases, promotion gates, decisions reserved for a human.
  • research/ — investigations that open by stating they changed nothing and naming the window they looked at. Explicitly not commitments.
  • guide/ — user-facing docs, read at build time and rendered inside the product.
  • design/ — mockups and prototypes.
  • archive/ — plans whose feature shipped, moved rather than deleted, each stamped with the date and branch that delivered it.
  • changelogs/ and postmortems/ — what shipped and what broke, with timelines.
  • Audits — the date is in the filename, so staleness is visible without opening it.

A spec of record, in its first four lines

# Watchbird - Pre-Trade Signal Intelligence
  (Spec of Record)

**Status:** Phase 0-0.5 (shadow) merged; Phase 6
enforcement landed 2026-08-21 for ACCOUNT-RISK
rules only. Market-context rules remain SHADOW
ONLY - they cannot change, delay, or drop a
trade.
**Roadmap:** pipeline/WATCHBIRD_PLAN.md - phases,
promotion gates, infrastructure.
**Siblings:** WATCHDOG_FREEFORM_RULES.md (the
machinery Phase 5 clones), WATCHDOG_EXTENDING.md
(shared invariants).

## 1. What this is

The watchdog watches POSITIONS after entry. The
watchbird looks at an incoming ENTRY signal
before an order exists, and answers: what is the
market context this trade is stepping into, and
what would a careful trader do about it?

Four lines do the work. The title declares the genre, so nobody mistakes it for a plan. Status says which part enforces and which only advises, with the date — then states the negative outright: the shadow rules cannot change, delay, or drop a trade. That sentence stops a reader granting the system more authority than it has. Roadmap points at where it is going. Siblings point at the machinery it borrows and the invariants it shares.

An agent landing there knows what is true, what is planned, what it must not assume, and where to look next — before reading a line of code. A document that only described the feature leaves all four to inference, and inference arrives with full confidence.

Two later headings are worth stealing. Honesty guards — why a reading is null instead of wrong points the anti-hallucination rule at the product: when a metric cannot be computed, the system returns nothing rather than a plausible number. Extending — the seams, cheapest first tells the next person where to cut, in order. That is the difference between a spec that documents a system and one that hands it over.

When the shape is a diagram

Its sibling spec looks nothing like it, and that is the point: shape follows the question. Watchbird’s hard part is vocabulary — what each metric means and when a reading can be trusted. The watchdog’s is sequence, so its spec is one picture.

positionMonitorService tick - every 10s
        |
        v
mark fetched for an open position
        |
        v
peakTracker.observe()  folds the mark into the
        |              high-water mark, seeded
        |              from the DB so a mid-day
        |              deploy cannot reset a peak
        v
watchdogEngine.evaluatePosition(snapshot)
        |
        v
freeformEvaluator - THE DETERMINISTIC GATE
   pure, runs every tick
   scope match? all conditions hold?
        |
   no --+--> nothing happens
        |
   yes -+--> verdict
             |
  decision:            decision:
  "deterministic"      "llm"
             |              |
             |              v
             |   per-(rule, position) cooldown
             |              |
             |              v
             |   the model, given: the trader's own
             |   sentence, the approved examples,
             |   every metric reading for this tick,
             |   and four verbs only -
             |   flatten | tighten | alert | hold
             |   8s timeout, then no action
             |              |
             |   hold / error / timeout -> nothing
             |              |
             |   escalation guard: may de-escalate,
             |   never exceed the verb the trader
             |   authorised
             |              |
             +--------------+
                    |
                    v
          engine.dispatch()
            - close position / update stop
            - append-only ledger row
            - in-app alert

Read as documentation, it gives the order of operations. Read as a specification of authority, it says the model is never the first thing to run. A deterministic gate evaluates every position every tick, in pure code. The model is consulted only for rules that asked for judgment — then handed four verbs, a cooldown, an eight-second timeout that fails to no action, and an escalation guard that lets it soften but never exceed the verb the trader authorised. Every edge is a constraint somebody chose. A paragraph loses all of them.

Keeping each layer true

A plan whose feature ships moves to the archive that week. The monthly pass fact-checks the two or three specs least recently touched. Layering helps only while the layer a document sits in is still true.

How Documentation Stops AI Agents Hallucinating

An agent’s failure mode is confident wrongness. Give it a plausible field name and it writes a query around it, gets an empty result, and explains the empty result to you. Give it a tool name that no longer resolves and it invents an authentication step to explain the failure. None of it looks like a mistake while it happens. It looks like work.

Write documents that correct the reader

Not documents that describe the system. The logs runbook:

  • lists the fields you can actually query — then says, in its own voice, that three fields it used to list are not in the catalog and must not be extracted;
  • warns that the file and line attached to every log line point at the logging wrapper, not the real call site;
  • records that the MCP’s tool names changed, lists every old one, and states plainly that each resolves to nothing;
  • dates its verifications, so a reader knows how old each claim is.

That is a different genre: a list of the specific wrong turns a competent reader will take, written at the fork. Dead citations are bugs for the same reason — an issue pointing at a line where the behaviour no longer lives sends the next reader on a detour.

Memory: the corrections too small for a doc

One file per correction, behind an index that is the first thing any agent reads. Mine is scar tissue. Here are the first few, project specifics stripped:

# Memory

One file per memory, named <type>_<slug>.md:
  feedback  - how to work in this repo
  project   - ongoing work and constraints
  reference - external facts worth caching

This index is the first thing an agent reads.
One line each: what it is, and the hook.

- [Never push to the default branch](feedback_no_push.md)
  - ask first, every time
- [Keep the long-lived branches](feedback_keep_branches.md)
  - exclude them from any cleanup
- [No branch switch mid-pipeline](feedback_no_switch.md)
  - it kills the running batch
- [Everything is insert-only](feedback_immutable.md)
  - never UPDATE; newest row is the current value
- [<file> is protected too](feedback_protected_extra.md)
  - ask before editing, though it is not on the
    explicit do-not-modify list
- [Build hits the live database](project_build_prod.md)
  - a local build's first tick runs against prod;
    make new queries safe on first run

...

Each file holds one fact, why it exists and how to apply it. The index loads before the agent does anything, so a rule is in context when it matters, not in a document nobody opened. Three entries, three jobs:

  • Never push to main without permission — stops an irreversible action. One line, written the day it was needed, that removes a whole class of mistake from every session after it.
  • Everything is immutable — stops plausible, wrong code. Nothing in the schema prevents an agent writing a perfectly reasonable UPDATE, and it would pass review. It would just quietly overwrite the history the rest of the system reads back.
  • The pricing helper is protected pipeline — amends the rules themselves. That file was never on the original protected list, and the one-line memory that added it is why nothing autonomous has touched it since.

One stops an action. One stops code from being written. One grows the guardrails. A correction made in conversation is gone by the next session; written to a file, it is the first thing the next session knows. The model forgets. The record does not.

The same rule, pointed at users

The product ships its documentation under the same rule: what happens between an alert firing and an order existing, stated plainly, with the cost of each behaviour named instead of its implementation. The page gets rewritten whenever it drifts back into the codebase’s voice — internal flag names in a user guide mean the doc stopped being written for the reader.

Matador's in-app documentation page explaining the notifications cascade in plain language
The product's own docs page: the signal-to-order cascade in plain language, with what a repeated alert actually costs you spelled out — and no internal flag names in sight.

Why this is the part that compounds

The compounding asset is the written record. The agents and the prompts get rewritten every few months. Every sweep adds a catalog row. Every incident adds a correction. Every groom turns prose into a queryable field. Tomorrow’s agent starts from a better description of reality than today’s did, because of what today’s agent wrote down. That is the real self-upgrading part. The dependency pull requests are housekeeping.

What These Agents Never Do

The limits, stated plainly:

  • The sweep needs my laptop. A cloud routine exists and is disabled: a cloud checkout inherits none of what reading production logs requires, so it could only report “no log source reachable”. The reason is written next to the switch.
  • No SQL against production. No production state changes.
  • Decisions are mine. Merges are mine.
  • The first run of anything outward-facing waits for a yes — security patches being the one exception, because the patch is the point.

This spends my judgment on the decisions, the merges and the six files, by refusing to spend it on grooming, triage, dependency patches, or remembering that a particular error at six in the morning is a laptop pretending to be production.

The leash is what makes the autonomy usable.

Steal My Agentic Playbook

Follow my progress as I ship new builds, orchestrate AI agents, and post field notes from the studio. No spam — just signal.

Norik.io · Business · Technology · Strategy