Skip to main content

How We Work Together

Status: Living document. Started 2026-08-07, after enough real friction from file-by-file guessing that it was worth writing down deliberately rather than continuing to rediscover the pattern each time.

Purpose: if you're a fresh Claude session reading this because Pete pointed you here — this is how we actually work, on top of whatever memory or project context you already have. Read this before diving into a task.


The core working style, established over months of real work

  • Ask for the real, current file before writing code against it. Never assume a file still looks like it did last time it was shown — codebases drift, and guessing wrong costs more time than asking costs.
  • Check, don't guess. Root-cause things from actual evidence — logs, database queries, correlation IDs — before proposing a fix. "That's probably it" is a hypothesis to verify, not a conclusion to act on.
  • Match existing conventions, don't invent new ones. Ask for a reference example before writing something that should follow an established pattern (a hook shape, a modal component, an endpoint structure).
  • Layer by layer on real feature work. Domain → application → endpoint → frontend, confirming each layer works before building the next one on top of it.
  • Capture what you find, even off-topic. If something's broken or inconsistent while working on something else, don't silently fix it or silently ignore it — log it (a ticket, a comment) and decide deliberately whether it's worth doing now or later.
  • Real architectural decisions get written down. ADRs exist so the reasoning survives past the ticket that prompted them — see adr-ticket-photo-display-access.md for the pattern.
  • Own mistakes plainly, then move on. No excessive apologizing, no defensiveness — just "here's what was wrong, here's the fix."
  • Keep Linear honest. Tickets should reflect what's actually true, not what was true when they were filed. Stale priorities and statuses get corrected as they're found, not left to accumulate.
  • Don't let scope balloon. When a conversation starts pulling toward designing multiple unshipped systems at once, that's a signal to scope down, not a green light to keep going. Bounded, sequenced work beats sprawling planning sessions.

The three-way process: Pete, Claude, and Claude Code (CC)

Why this exists: a real pattern of wasted time — Claude guessing which file might hold an answer, Pete uploading it, Claude realizing it needed a different file too, repeat. Established 2026-08-07 to fix it directly.

Division of labor:

  • Claude Code (CC) has full, always-current access to the actual local repo. It's the ground-truth layer — deep exploration, multi-file verification, "does this pattern exist elsewhere too," actually confirming what's real rather than working from what was shown three conversations ago.
  • Claude (this chat) stays the planning and diagnosis layer — reading production evidence, root-causing from logs, making architecture and product judgment calls, keeping Linear accurate, writing clear specs for CC to execute against.
  • Pete relays between the two. There's no automatic connection — Claude can't reach the filesystem, CC can't reach this chat. Pete is the bridge, deliberately kept lightweight.

Day-to-day feature work stays exactly as it's always been — Claude writes code in chat, Pete copies it in by hand. This process is specifically for the pattern below, not a replacement for how we normally work.

When to invoke this process — a real trigger, not a vibe:

If we've asked for a third file trying to resolve the same question, or gone in a circle twice without landing anywhere — that's the signal. Either Pete or Claude can call it.

The mechanic — a shared scratch document, relayed by hand:

  1. Claude (or Pete) identifies a real, bounded question that needs verification against the live codebase — not "look around," a specific thing to confirm.
  2. Pete gives CC a clear, scoped prompt asking it to investigate that specific question and write its findings into a scratch file — something like INVESTIGATION-TRA-XXX.md, named after whatever ticket or issue prompted it.
  3. Pete pastes or uploads that file into the chat with Claude.
  4. Claude reads it as ground truth, diagnoses or plans against it, and if something further needs checking, writes that follow-up question back into the same document for Pete to hand back to CC.
  5. Once resolved, the scratch file gets archived or deleted — it's disposable working memory for one question, not a permanent artifact like an ADR or the implementation plan.

Tests are part of the deliverable, not a follow-up (added 2026-08-11)

Not full test-first TDD — that's real ceremony that doesn't pay for itself on a quick config fix or early exploratory UI work. The lighter, always-applicable version: when CC builds or changes real behavior, tests for that change land in the same pass, by default — not deferred to a separate ticket "for later." Tonight's TRA-369 remediation is the proof this already works when asked for explicitly (15 new tests landed alongside the fix, not queued separately) — the gap has never been whether this works, it's been that it was something we happened to ask for instead of the default.

This is also directly connected to "verify real wiring" above — a change with no test is exactly the kind of thing that can silently become the next TRA-369/TRA-402 finding, since nothing would catch it drifting later.

Verify real wiring, not just presence (added 2026-08-10)

A file existing, compiling, and looking complete proves nothing about whether the live app actually calls it. Real example: useTechMutations.ts was a well-built, fully-implemented offline-mutation hook — optimistic updates, rollback, queueing, all correct — with zero live callers anywhere in the app. Worse, the queue's read side (useSyncStatus, SyncStatusBar) was live and rendered to real users, silently reporting "synced" while the only code path that could ever populate that queue was unreachable. A visible UI element actively telling someone their work is fine, when it might not have been recorded at all.

This isn't a one-off. The original TRA-358 investigation found the same shape of bug on the backend months earlier — SubscriptionEnforcementBehavior correctly built and wired into the pipeline, but the domain methods it depended on (ActivateSubscription, ExpireTrial, etc.) had zero usages anywhere. "Looks complete, never actually called" is a real, recurring failure mode in this codebase, not a fluke.

Default practice: whenever CC (or Claude) investigates a hook, service, component, or domain method, confirm real call sites exist in live-rendered code or actually-invoked paths — a grep for every exported name, checked against what's genuinely reachable — as a first step, before treating "the file exists and looks right" as evidence it works. This is a different question than test coverage, and answering it took a specific instruction the one time it mattered; worth making it standard instead of something we happen to remember to ask for.

Capture cross-product findings, not just RoundTrip ones (added 2026-08-09)

Real pattern across the last several days: things come up while working on RoundTrip that actually belong to the bigger Traxs platform, not RoundTrip specifically — TRA-371/372/373 (Proposal Builder, Service Agreements, self-service booking), TRA-386 (Command Center monitoring), and the M365/cross-product Entra identity question below. Easy to lose these in the shuffle since there's no separate Command Center project to file them under yet.

Default: capture these in Linear too, same as everything else — filed under RoundTripAPI (the only project currently accessible), explicitly labeled as product-undecided rather than a RoundTrip commitment, same as TRA-371/372/373 already do. Don't let "this isn't really a RoundTrip ticket" be a reason to not write it down.

TRA-225 already has real, substantive Command Center scoping material — actual route definitions, architecture pattern, Relay's positioning — sitting in its own description from months ago. Worth treating as the actual starting reference whenever the real Command Center planning session finally happens, not something to reconstruct from scratch.

Default to logging findings, not remembering them (added 2026-08-09)

When an investigation (CC's or otherwise) surfaces something real — a gap, a bug, an open question — log it in Linear as its own scoped item by default, rather than deciding case-by-case whether it's "worth" a ticket. The judgment call itself costs time and risks losing something smaller-seeming that turns out to matter later (TRA-152/TRA-165's shared dependency, TRA-384's collision-vs-domain-redirect distinction — both were nearly-missed nuances caught only because the surrounding findings got written down properly).

The one exception: something CC or Claude explicitly identifies as needing an immediate direct fix rather than a ticket (a live, active bug — e.g. TRA-388's Finding A, duplicate axios interceptors doubling Entra load on every request) — name that clearly as "fix now" rather than filing it and letting it wait in a queue.

Check the case-study archive before assuming drift (added 2026-08-08)

RoundTrip has a real, detailed case-study archive going back to the project's start — every real session, in Linear's Resources/Documents section under the RoundTripAPI project, going back to March 2026. These aren't just changelogs; they capture why a decision was made at the time, including dead ends that were tried and abandoned for good reasons.

Real example this caught: investigating why ProvisionTenantJob and a team-invite handler used different Entra user-creation methods, the instinct was to assume confused, accidental drift. The archive showed the opposite — a deliberate, well-reasoned fix (TRA-223) made after hitting real production bugs with the original approach. Assuming drift where a documented decision actually exists wastes time and risks undoing something that was fixed for a real reason.

Before CC (or Claude) concludes something is stale, confused, or accidental drift, check whether a case-study document already explains it. Linear:list_documents (filtered to the RoundTripAPI project) surfaces the list; Linear:get_document pulls a specific one. Worth doing this before building a theory from code alone, not after.

Test-currency checks (CC task, added 2026-08-07)

Real, recurring pattern found repeatedly this project: tests silently drifting out of sync with the code they're supposed to cover — TenantTests.cs missing coverage for real domain methods (TRA-364), orphaned Playwright spec files never actually running (TRA-366's investigation), test locators assuming a native <select> that had long since become a custom component. None of these were caught until something else forced a closer look.

Proposed as a periodic or on-demand CC task, not an automatic background process — CC doesn't run on its own schedule, Pete triggers it:

  • Scan for methods/endpoints with no corresponding test coverage
  • Scan for test files referencing signatures or components that no longer match the real implementation
  • Check for test files that exist but aren't included in any actual run configuration (same shape as the dispatch-board.spec.ts discovery)

Output should be the same pattern as everything else here — a written findings document, relayed to Claude, turned into real Linear tickets for genuine gaps (matching how TRA-364 itself came out of exactly this kind of manual audit). Worth running this after any substantial feature lands, not just when something's already suspected to be wrong.