Resources / Working with AI
Scaffold the decisions that matter.
Give the agent a concrete place for each responsibility, and a way to tell whether it stayed within those boundaries.
More than an empty folder tree.
A scaffold records decisions before implementation. It can include directories, module names, signatures, comments, examples and tests. The useful part is the responsibility each piece makes explicit.
Who owns this behaviour?
One module owns expiry policy. Other layers call it rather than implementing their own version.
Which way do dependencies flow?
The domain knows nothing about HTTP or the database. Adapters translate between external systems and application contracts.
What crosses the boundary?
Types, units, errors and examples define the contract. A timestamp must say whether it is seconds or milliseconds.
How will it run?
Name the deployment target, configuration, persistence needs and existing commands. Do not let the agent invent a second deployment path.
In an existing project, start with its actual conventions. Do not impose a new architecture just because a template looks tidy.
Original teaching example
An invitation-acceptance feature
Scope the behaviour first: an invitation can be accepted once, before its expiry. The same instant is supplied to every policy check. The storage operation must prevent two concurrent requests from both accepting it.
Place the responsibilities
src/
domain/
invite.ts # expiry policy and domain types
invite.test.ts # boundary examples
application/
accept-invite.ts # use case and repository interface
adapters/
invite-store.ts # implements persistence
http/
accept-invite.ts # validates input, maps response
docs/
invite-contract.md # behaviour and trade-offsSketch the contract
type Invite = {
id: string;
expiresAtMs: number;
acceptedAtMs: number | null;
};
type Acceptance =
| { ok: true; invite: Invite }
| { ok: false; reason: "expired" | "already-accepted" };
// Pure policy. No database, HTTP request or system clock.
// Expired means nowMs >= expiresAtMs.
export function acceptInvite(
invite: Invite,
nowMs: number
): Acceptance {
throw new Error("Not implemented");
}This is a deliberately incomplete scaffold, not production-ready invitation code. The throwing stub makes missing implementation visible. Authentication, token verification, persistence and concurrency still need implementation and tests.
- Before expiry
- At 999 ms with expiry at 1,000 ms, acceptance succeeds.
- At expiry
- At 1,000 ms, return expired. The boundary is inclusive.
- Already accepted
- Return already-accepted, with no second side effect. Check this before expiry so the error precedence is explicit.
- Concurrent requests
- At most one storage operation succeeds. A pure function alone cannot enforce this.
- Dependency boundary
- A domain import of the database adapter fails an architecture check.
Turn the sketch into checks.
One owner for expiry policy
Fill the contract in place
Boundary tests and import rules
The scaffold supplies forward pressure. Behaviour tests, dependency rules and code review supply back pressure. A folder name does not prevent an invalid dependency; an executable rule can.
A delegation brief for this example
Implement the invitation acceptance use case.
Use the existing module boundaries and deployment command.
Read docs/invite-contract.md and the nearby adapter first.
Put expiry policy only in domain/invite.ts.
Do not add dependencies or change the public API.
Add boundary and concurrent-acceptance tests.
Report the diff, commands run and unresolved assumptions.
Stop if the persistence API cannot enforce one acceptance.What if the scaffold turns out to be wrong?
Stop and explain the conflict with a concrete example. Amend the contract and its tests together after reviewing the trade-off. Do not preserve a bad design merely because it was written first, or silently bypass it with a duplicate implementation.
How much is enough?
Scaffold expensive decisions
Spend time on data ownership, security boundaries, dependency direction and deployment. Use one end-to-end example to expose gaps before filling many files.
Leave ordinary details open
A scaffold should reduce risky guesses. Specifying every helper and loop can slow learning and encode decisions you have not tested.
If the language or domain is new to you, inspect a few relevant open-source projects, compare their trade-offs, and ask an experienced person to challenge your sketch. Test a small proof of concept before treating the structure as settled.
Review early enough to recognise drift. If an isolated attempt is unusable, keep the learning and discard only that attempt after preserving anything valuable. Never erase unrelated work.
Ideas from the interview
Beyond Coding's guest describes manually creating folders, comments and signatures before delegating. He also makes product and deployment decisions explicit. The invitation scaffold above is a new example, not code from the video.
- 12:11 · Files, comments and signatures
- 15:56 · Learning patterns before scaffolding unfamiliar code
- 41:46 · Boundaries, core files and richer data contracts
- 71:50 · Product intent, architecture and deployment
His experience of model strengths and weaknesses is a report of his workflow, not a guarantee about every model or codebase.