Duxbury Tech · Internal · Access-gated

Agent & Knowledge Stack

Where data comes from, which agent touches it, where it comes to rest, and what is not wired yet. Operational reference — file paths and credential locations are real.

Studio + MBP · verified 2026-08-22

01Data flow

Left to right is chronological. Work does not start at Jira — Jira's only inbound-to-agent edge is the agent-ready dispatch, drawn as the return loop it actually is.

CAPTURE — ORIGINS PROCESSING SYSTEMS OF RECORD SYNC & BACKUP Teams / Google Meet recordings + transcripts Granola meeting notes Joe direct instruction · session start zero — scheduled task weekdays 18:00 Claude Code primary · holds session state ~/.claude/…/memory · git-tracked Codex peer reviewer · council MCP ~/.codex/AGENTS.md Notion engagement logs · Activity Log Obsidian vault source of truth · NOT git-tracked └ Knowledge/inbox Codex write boundary Jira duxburytech.atlassian.net GitHub account Z350C001 Trackers ~/trackers · git · Studio ↔ MBP zero — ZeroCoolVault rclone copy · never deletes Tailscale 100.105.220.108 Codex local state ~/.codex/*.sqlite memories · threads · history one entry per meeting Teams → session: leaves no record council MCP read + write MCP + REST write = inbox only agent-ready dispatch — session start rclone additive NOT SYNCED
agent / capture path scheduled or automated sync feedback loop broken or absent edge

zero is an actor, not just a sink. It runs the Granola→Notion sync on a schedule. The Studio only hosts granola-watchdog.sh, which fires at 19:15, stays silent when healthy, and alerts by Telegram when a run goes missing.

02Every edge

Mechanism and path for each connection, so a failure traces to a specific file rather than a guess.

From → ToDirectionMechanism
Teams / Meet → GranolacaptureMeeting notes captured at call time
Granola → NotionscheduledTask on zero, weekdays 18:00 — one Activity Log entry per meeting
Teams / Meet → Claudead hocTranscripts read directly into a session. Leaves no record unless written out
Claude ↔ Obsidianread + write~/Documents/Work/Knowledge — CLAUDE.md hot cache → memory/ depth
Claude → NotionwriteClients DB deedb5be…; append timeline row at top of current month, set Last Activity
Jira → Claudedispatch~/bin/jira-agent-ready.sh SessionStart hook · POST /rest/api/3/search/jql
Jira → Obsidianone-wayTASKS.md in vault root. ClickUp is retired
Claude → GitHubread + writegh CLI · token in macOS keyring · scopes gist, read:org, repo, workflow
Claude ↔ Codexpeercouncil MCP both sides · ~/bin/council-codex.sh launches Codex into the session
Codex → Obsidianread onlydisk-full-read-access — reads the whole vault
Codex → inboxwrite onlyKnowledge/inbox/ is the sole writable vault path; Joe or Claude triages into memory/
Codex → NotionreadMCP https://mcp.notion.com/mcp · OAuth · read tools pre-approved, writes default-deny
Codex → GitHubread + writeMCP api.githubcopilot.com/mcp/ · bearer GH_TOKEN
Codex → Jiraread + writeREST direct · creds ~/.config/zerojira/.env. No MCP by choice
Vault + trackers → zeroadditive~/bin/zero-hub-sync.sh · rclone copy, never deletes · Tailscale 100.105.220.108

03Known traps

Each of these has already caused a real failure or is one step away from doing so.

One Salesforce identity, shared key store

Codex runs sandboxed and cannot reach the macOS Keychain, so its sf falls back to ~/.sfdx/key.json and re-encrypts every auth file. The next unsandboxed sf then fails to decipher. Both tools are pinned to the file key, so this is contained — but both agents still act as the same Salesforce user.

There is no supported way to give Codex its own store: Global.SFDX_DIR is hardcoded to os.homedir(), not an environment variable. The only real separation is identity — a distinct SF user for Codex, with its own permission set.

Pinned in ~/.zshenv and ~/.claude/settings.json · SF_USE_GENERIC_UNIX_KEYCHAIN=true · never re-authenticate to fix this

Auth failure presents as a silent empty result

A query helper that swallows exceptions returns [] rather than raising. During the WA conference load this wrote a garbage 441-row file over a good client deliverable.

Wrap sf query helpers in retry + a hard assert on expected row count

The vault has no undo

~/Documents/Work/Knowledge is not a git repository, and it is the source of truth. zero's copy is additive so old files survive, but an overwrite propagates on the next sync.

Codex writes to inbox/ only — --add-dir grants write, so the vault is deliberately excluded

gh reads as logged-out inside the sandbox

The gh token lives in the keyring, which the sandbox cannot read, and Codex's default environment policy strips *TOKEN* from the child shell. The MCP path works because Codex reads GH_TOKEN in its own process before the sandbox applies.

Expect gh shell commands to fail; use the GitHub MCP instead

Recording policy vs. the capture layer

One engagement carries a no-AI / no-recording policy, and its calls are in Granola. That sits directly on the capture path drawn above. Written sign-off was drafted and is not sent.

Unresolved — the missing item is authorisation, not deliverables

04Not wired

Gaps that are real but not yet failures.

Nothing flows out of Notion

Engagement logs go in and are read by humans. No agent reads engagement history back as context before starting work. That edge does not exist.

Codex local state is a silo

~/.codex/*.sqlite holds its own memories, threads and history. Nothing syncs it to the vault or to zero — the crossed edge on the right of the diagram.

Transcripts have two paths, only one leaves a record

Via Granola they reach Notion on a schedule. Read directly into a session, they leave nothing behind unless deliberately written out.

MEMORY.md truncates silently past ~24.4KB

Entries at the tail are dropped before load with no error. One line per entry; detail belongs in topic files.