Customer interviews in, shipped secure features out.
Demo video:
Founders are told to talk to their users, so they run 10–50 interviews. Then the insights end up in scattered notes and docs and get forgotten. Patterns get missed ("7 people asked for this"), contradictions get missed ("the new customer says the opposite"), and features get built on gut feel.
- Pre-seed to Series A founders who run their own customer interviews.
- Small product teams that don't have a dedicated user researcher.
Five agents and one human work in a single Band Desktop room. Each agent's instructions are in agents/.
| Agent | Band handle | Harness | Job |
|---|---|---|---|
| Trust Agent | @nod-trust |
Claude Code | Redacts private data from transcripts, runs Snyk on every finished card, blocks or completes it |
| Listener | @nod-listener |
Claude Code | Turns each interview into one structured insight per customer (pains, requests, verbatim quotes, sentiment) |
| PM | @nod-pm |
Claude Code | Recalls every insight, counts customers per request, flags conflicts, writes the ranked plan and cards |
| Skeptic | @nod-skeptic |
Codex | Rejects any card that isn't backed by at least one real customer quote from memory |
| Builder | @nod-builder |
Codex | Recalls past security lessons, writes the code in invoiceflow/, hands off for a scan |
| Founder | (human) | Band | Picks the feature, decides on high-severity security issues, approves credit top-ups |
Founder uploads interview
→ Trust Agent: redact.py → @Listener
→ Listener: meter balance → extract → remember insight → meter interview_analyzed → @PM
→ PM: recall all insights → patterns + conflicts → cards → @Skeptic
→ Skeptic: recall quotes → approve/reject → @Founder
→ Founder picks a feature → @Builder
→ Builder: recall lessons → code → @Trust Agent
→ Trust Agent: scan.py + meter security_scan
✗ block card, @Builder with the fix, remember lesson
✓ card to Done; Builder remembers the feature, meters feature_shipped
- One room. All five agents and the founder share one Band room and one board.
- Cards. The PM creates cards with
band work assign. The Builder claims one withband work take. The Trust Agent blocks or completes it withband work room-status. - Handoffs. Every handoff is an @mention, so the room reads as a log of who did what.
- Founder in the loop. Agents ask the founder through
band askfor three decisions: which feature to build, how to handle a high-severity security issue, and whether to top up credits. - Cost per agent. Band's Overview/Analytics view shows what each agent spent.
Every agent shares one memory that lasts across sessions. There are three kinds of record, each in its own Cognee dataset. The shapes are in CONTRACTS.md.
| Kind | Written by | Read by |
|---|---|---|
insight |
Listener (one per customer per interview) | PM (all insights before every plan), Skeptic (quotes per card) |
lesson |
Trust Agent (when Snyk blocks a card) | Builder (before writing any code) |
feature |
Builder (when a card ships), PM (when a conflict supersedes one) | PM |
What the tools do (with NOD_USE_COGNEE=1):
tools/remember.py --kind K --json '<record>'always appends the record to the local storememory/store.jsonl, which gives it an_id. It then adds the record (tagged with_idand_kind) to the Cognee dataset for that kind and runscognify. It keeps Cognee's data id in.cognee_ids.jsonso the record can be deleted later.tools/recall.py "<query>" [--kind K] [--limit N]runs two Cognee searches:GRAPH_COMPLETIONfor a short answer andCHUNKSfor the source text. It pulls the original JSON records back out of the chunks, drops any that were forgotten, and returns{"answer":..., "results":[...]}. An empty query uses a default question for that kind. Empty memory returns no results instead of an error. If Cognee fails, it falls back to keyword search over the local store and reports"backend": "local (cognee error)".tools/forget.py --customer <name> [--topic <word>]or--id <_id>marks the matching records as forgotten in the local store and deletes them from Cognee using the saved data ids.
What memory changes:
- Across a full restart. Cognee's storage is in the repo (
.cognee_system/,.data_storage/), so killing every agent loses nothing. In Round 2 the team restarts, and the founder uploads a new interview from Tom. The PM recalls Sarah, Mike and Priya from earlier sessions and names them. It flags that Tom finds automatic reminders annoying while Sarah and Mike want them, then resolves it as "reminders optional per client". It also moves multi-currency up now that it has 2 requests (Priya, Tom). - Between agents. In Round 1 the Builder hard-codes an API key, Snyk blocks the card, and the Trust Agent saves a lesson. After the restart, the Builder recalls that lesson, reads the key from the environment instead, and passes Snyk the first time.
- Forgetting. When a conflict changes a decision, the PM forgets the outdated feature record by id ("always on for every client") and saves the replacement. Customers' own insights are kept, so the counts stay right. They are only forgotten if that customer changes their mind or churns.
- On every finished card, the Trust Agent runs
tools/scan.py invoiceflow/. That callssnyk code teston the code andsnyk testoninvoiceflow/requirements.txt. - Medium, high or critical issues block the card (exit code 1). Low-severity issues are reported but don't block. If the Snyk CLI isn't available, the scan falls back to a local check for hard-coded secrets and reports
"source": "local". - On a block, the Trust Agent posts the file, line and fix to the Builder and saves a
lessonto Cognee, so the same mistake isn't repeated after a restart. - Privacy: every transcript goes through
tools/redact.py(emails, phone numbers, card numbers, IBANs) before anything is stored.
| Event | Credits | Sent by |
|---|---|---|
interview_analyzed |
1 | Listener |
security_scan |
1 | Trust Agent |
feature_shipped |
5 | Builder |
tools/meter.py event <name>sends the event to Flexprice for theinvoiceflow-democustomer and deducts the credits.- Credit gate. Before analyzing an interview, the Listener runs
tools/meter.py balance. At zero credits that command exits with code 2, so the agent stops and asks the founder to top up throughband ask. Runningtools/meter.py topup <N>adds credits to the Flexprice wallet. - Where the balance comes from. The gate reads a local ledger by default. Setting
NOD_GATE_FROM_FLEXPRICE=1makes it read the Flexprice wallet instead.
| Plan | Price | Credits |
|---|---|---|
| Free | $0 | 20 credits |
| Starter | $29/mo | 200 credits/mo |
| Team | $99/mo | 1,000 credits/mo + shared team memory |
| Top-up | $10 | 100 credits |
| Remembers customers | Finds patterns | Builds features | Security checks | |
|---|---|---|---|---|
| Notion / Google Docs | Manually | No | No | No |
| Dovetail | Yes | Yes | No | No |
| Devin-style coding agents | No | No | Yes | Not by default |
| Nod | Yes | Yes | Yes | Yes, blocks on Snyk |
Python 3.10–3.12 is required (Cognee won't install on 3.9). On a Mac:
brew install python@3.12.
python3.12 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # fill in the keys (ask the team; never commit .env)
brew install snyk-cli && snyk authEvery tool has a local fallback, so this quick test works before any keys are set:
python tools/redact.py data/interviews/sarah.txt
python tools/remember.py --kind insight --json '{"customer":"Sarah","requests":["auto payment reminders"],"quotes":["I hate chasing late payments."]}'
python tools/recall.py "payment reminders" --kind insight
python tools/meter.py balance
python tools/scan.py invoiceflow/To use the real services, set NOD_USE_COGNEE=1 and NOD_USE_FLEXPRICE=1 in .env.
bash scripts/snyk_check.sh # plants a hard-coded key: the clean app must pass, the planted key must be blocked
./scripts/reset_demo.sh # clean demo take: wipes local memory and the ledger, resets invoiceflow/ (Cognee is kept)
python invoiceflow/app.py # the demo app the Builder edits, on http://localhost:5050tools/ CLI scripts the agents call (interfaces in CONTRACTS.md)
agents/ Instructions for each agent
data/ Demo interviews (InvoiceFlow customers: Sarah, Mike, Priya, Tom)
invoiceflow/ Small Flask app that the Builder edits
scripts/ snyk_check.sh, reset_demo.sh
memory/ Local fallback store and credit ledger (git-ignored)
| Owns | |
|---|---|
| Person A | Band room and agents: harnesses, agents/*.md, the board and handoffs |
| Person B | Memory and data: Cognee, remember / recall / forget / redact, the interviews |
| Person C | Code, security and billing: invoiceflow/, Snyk (scan.py), Flexprice (meter.py), submission |