apeg.dev/Forward deployed engineer/How it runs

Forward deployed engineering · September 2026

Forward deployed engineering: how an engagement works, week by week

A forward deployed engagement runs on five habits: decisions written before code, something usable every week, quality rules checked by the compiler, stand-ins for outside services, and a clear handover.

In September I moved a client's marketing site to a new host. It was built and cut over the same day, with the owner's OK, then checked against a list of 29 addresses: same pages, same titles, same analytics tag, every old redirect still redirecting, the 404 page still a 404. The first build on the new setup deployed in about a minute. The move went well because of what had been written down in the months before it, and that is what this page is about.

Most explanations of forward deployed engineering are frameworks: five phases with week numbers, usually written by a staffing firm or a software vendor. This is not one of those. It describes how the model ran inside a founder-led company over eight months, taken from the notes, handoff documents and review records I kept at the time, with the numbers left in.

Where this comes from

One engagement inside a founder-led company, January to September 2026, as the only engineer. The sources are the decisions file, the weekly ship log, the gate configuration in the repository, six rounds of written review corrections, ten handoff documents across four codebases, and the commit history: about 2,900 commits against 111 tracked issues. The team section draws on a second engagement, a retail platform led for nineteen months with seven contributors, from its repository history. Sector and scale are stated. The company, its product, its city and its people are not, by agreement. Nothing here is reconstructed from memory.

The short answer

A forward deployed engagement runs on five habits: the owner's decisions are written down before any code; something usable ships every week through a real channel; the quality rules are enforced by the compiler, not written in a document; every external service has a stand-in so credentials never block; and it ends with a handover a stranger could follow. The rest of this page is the detail behind each one.

The engagement in numbers

MeasureFigureWhere it comes from
Duration, one engineer8 months, January to September 2026commit history
Commits against tracked issuesabout 2,900 across 111 issuesrepository
First thing shipped end to enda login page, as 3 issues: backend, screen, wiringissues 1 to 7
Gates on every merge4: tests, lints, the front-end test suite, the formatterthe workflow document
Review subagents per change3, run in parallelthe workflow document
Written review-correction rounds on one feature6the review records
External services with a real and a mock implementation5: video, email, webhooks, custom domains, billingthe product README
Tests green with no vendor credential at all127 unit, 179 endpointthe product README
Handoff documents at the end10, across 4 codebasesthe notes folder
Addresses checked at cutover29the migration handoff

Every figure above is a count from a file, not an estimate. The measured before-and-after table further down is the same kind of number.

Before day one: write down the decisions that are not mine

The first thing I wrote on the engagement was not code. It was a table with two columns, human and engineer, saying who owns what. The owner writes the specs, reviews the issues and sets the order. I do everything between "this is ready" and "this is on the development branch". Underneath it, one line: the spec is the product decision and the owner owns it entirely.

Next to that table were the owner's rules, and they carried into every later session. No live change to the domain, the zone or the running site without his OK. Never probe a hostname before creating it, a mistake the project had already made once. Keep the analytics and search tooling exactly as they are. Plain English in anything he reads. Later, when the marketing work started, a second list appeared with a heading that made it binding: founder decisions, do not relitigate. Nine lines. Which data source is in and which is out. No phone calls to customers, ever. Which segment first. Which platforms get budget and which are an explicit extra.

The repository's own instruction file limited the scope in the same way: build exactly what is asked, nothing more. No "while we're here" additions. No error handling for situations that don't exist yet. Nothing outside the acceptance criteria. On another product the equivalent file was headed "locked decisions, do not deviate", and each decision carried the date it was agreed.

I used to read lists like this as something that slowed me down. Now I think they are what lets an engineer move fast inside someone else's business. Each line is a decision I don't have to make, defend or reopen, and a limit the owner doesn't have to enforce.

Week one: test the build process on something small

The first thing that shipped was a login page. Not because it mattered, but because it was the smallest thing that could go through the whole build pipeline end to end: a spec written from a static design, three issues in a fixed shape (the backend handler with mock data, the screen, the wiring between them), then plan, build, review, merge. The repository's issue history still shows it. Issues one to three are the login page, four is its database tables, and five to seven are the same three issues again, this time labeled merged. The build process was tested on a screen that did not matter, so when the video pipeline went through it a week later, the pipeline was the only new thing. I do this on every engagement now and I usually have to argue for it.

Week one also settles how the owner reviews. Here it was one action: add the "ready" label to an issue, from a browser or a phone. That label was the priority control. The owner decided what got built and in what order without opening an editor, and I never had to guess what was next.

Every week: ship something usable through a real channel

The rule for the weekly cadence is one sentence from the architecture document of another engagement, and I have used it everywhere since: every week ends with something usable via at least one real channel. Progress on the core engine that nobody can use does not count.

"Usable" was defined in advance so its meaning couldn't change later. On that engagement the channels were listed by week: engine core in weeks one and two, the web chat in weeks two and three as the first fully usable channel, the messaging adapter in weeks four and five, and the next platform held back until the earlier one had produced retention numbers. On the marketing work it was a fixed count from a fixed date: two videos a week from week three, twelve by day sixty, each title chosen in advance with its search volume next to it, so no week's output got negotiated inside the week.

What happens in a week where nothing ships? The records answer with measurement dates set in advance. The first read of the real conversion rate was set for week four, on the first 200 registrations. A separate engagement set a stop-or-continue checkpoint at weeks five to eight with numeric criteria, and a week-twelve decision with three named options: invest more, change the target customers, or stop. A silent week gets explained in plain English, with what blocked it and who unblocks it. Silent weeks happen. Hiding one is what counts as a failure.

Speed with safety: let the compiler enforce the quality rules

The engagement produced roughly 2,900 commits across 111 issues without a single pull request, and it did not ship code that panics. Those two things are connected. The quality rules were not a document anyone had to remember. They were a list of things the compiler refuses to accept. The lint configuration opens with its own rule: if it can panic or hide bugs, deny it. Then it does. Unwrapping a value that might not exist, denied. A placeholder that says "to do", denied. An unreachable branch, denied. A catch-all that swallows an error, denied. The front end mirrors it: no debug prints, no non-null assertions, no untyped values, and dead code is a build failure. A comment that says "fix later" cannot be committed. I set it up that way because I don't trust myself at 11pm, and I trust a coding agent at 11pm even less.

Around those rules ran a loop, and much of the building was done by coding agents inside it. One task per iteration, with a fresh context each time so earlier work does not clutter it. Search the codebase before writing, because the thing usually exists. Implement fully, no placeholders. Run every check. If any check fails, fix it and rerun all of them from the start. Commit with the issue and task number in the message, then confirm the commit exists and the working tree is clean, because code that is not committed can be lost. Mark the task done. Exit. The loop restarts clean. The twelve rules that govern it fit on one screen, and the last one is what makes the rest safe: every task is a git commit, every issue is a branch, so any change can be undone.

Review was three reviewers with narrow jobs, run in parallel, told to find problems and not fix them: one for error handling and process management, one for performance, one for the interface. Their rule with the build script allowed only two outcomes, and it was written after it was broken once: either add the findings as tasks or write the file that says the review passed. Do neither and the script merges the bugs you just found. An independent audit ran after the reviews, with a rule that every finding must cite the rule or spec line it violates, and that a good audit has five to fifteen findings. Twenty means most of them are not real problems.

Here is what that looked like on one feature, the deferred render, from the six rounds of review notes in the repository. Round one reviewed five commits and found fourteen items, the worst of them a publish that would silently ship a video with an old caption size still in it. Round two re-reviewed round one's fixes and found four new problems the fixes had introduced, including one where I had told the agent something true about database cost and wrong about the user's experience. The note says so: my mistake, let me correct it now. Round three found three deploy blockers, two of them the kind where a user publishes without their latest edit and never knows. Round four was two characters of SQL, an equals sign that had to become "in", because my own description of the race in round three had been wrong. Round five found a logo that had an enum value but no code path to draw it, found by clicking through the product rather than reading the code. Round six closed the three items that had been consciously deferred. Every round ends with its cost: about two hours, forty minutes, thirty, five, twenty, forty-five. About five hours over six rounds, for a feature estimated at ten to fourteen days.

Every round also declared itself final. "All known races are guarded." "Production-ready, for real this time." "Truly final. No more rounds. Ship it." Then round six, in capitals: "truly done". I'm leaving that in. It is the most honest record I have of how review goes in practice, and a customer who has been told "done" four times should know the fifth time was checked a different way.

Credentials and external services: never wait on a key

The slowest thing in every engagement I have run has been the customer's accounts. The payment processor, the video host, the email provider, the DNS zone, the API key that has to be issued by someone who is on holiday. So I build so that none of them can block anything.

Every external service is reached through one interface with two implementations: the real one, and a stand-in that records what it would have done. Which one runs is decided when the app starts, by whether the secret is present. Where two secrets are needed, both are required. On one product that covered video, email, webhooks, custom domains and billing, and the result was that the whole thing ran and tested with no cloud account and no external keys: 127 unit tests and 179 endpoint tests, the endpoint tests in a real worker runtime against a migrated test database. When the keys arrived, one environment variable turned each real service on and nothing else changed. On the next product the rule got tighter: in a shipped build the stand-in is unreachable, and a missing key produces an honest "not configured" rather than a fake result. The README says it in four words: no fabricated ad account or metrics.

The same rules apply to how secrets are handled. A public site never holds a key; its contact form posts to the app, which does. Keys are created by a local script that prints them once and stores only the hash. A secret is never pasted into a chat, and one that was gets re-issued as a named step in the handover. Where my own access token was deliberately limited, the note says who must act instead: the DNS records get added by the owner, because my token is read-only on the zone. That was the owner's rule from day one and it stayed the rule.

Platform rules you only learn by shipping

The constraints that cost the most time were not technical and were not ours. They belonged to the platforms we published to, and we learned them by trying to publish and failing. The product had to post to five of them, and each has a limit you only find when something fails. One refuses any link that is signed or expires, so the whole media store had to serve plain public URLs or nothing would post. The playbook marks it as the most dangerous, because it fails without an error. One caps unverified accounts at fifteen minutes of video, so a full-length upload fails without saying why. One shows a post to roughly 40 to 50 percent fewer people when it contains a link, so links go in the first comment. One takes no video at all, one image per post, and archives posts after about a week. One turned out not to have the requirement we had assumed, and the verification pass corrected our own note.

Every limit went into a playbook with a mark next to it: works as is, needs a change, can't do. The conclusion at the bottom is the useful part. Most of the "needs a change" items were the same three jobs, done once and reused: a step that asks "as is, transform, or skip" before scheduling, a check at connection time for the account type, and one public-URL guarantee that satisfied two platforms at once.

Infrastructure has rules too, and they go in the learnings files so they are learned once. Uploads over 100 megabytes were failing at the reverse proxy with a timeout, so uploads now go straight to storage on signed links and never touch the server. The host restarts containers without warning, which corrupted the database until writes were made fully synchronous; a check at startup now resets any job the restart left unfinished. A preview environment once inherited the production routes and took the live traffic, so the preview config now overrides them with an empty list. A health probe that polled the GPU kept it running day and night at about a thousand dollars a month. It was replaced with an on-demand check.

Measure before deciding

The build notes carry a number next to almost every decision. Without one it is an opinion, and I have plenty of those. A set from one engagement:

WhatBeforeAfterWhat changed
Render of an eleven-chunk video14 minabout 2 minchunks encoded at the same time instead of one after another
Merge step90 s38 sone encoder option the merge never needed, removed
Output size from a 439 MB source1.87 GB247 MBa quality setting backed off to one nobody could tell apart
Timed graphic overlay, per 90 s chunk0.08x, over 10 min3.4x, 26.5 stiming moved from the filter to the input, so the graphic is decoded only while it is on screen
Preview of a brand profile4 to 5 min15 to 90 srendered in the browser instead of on a server; zero server cost
Transcription of a fifteen-minute video117 s on a GPU2.4 smoved to a hosted speech model; the GPU path retired
Configuration surface50+ fields6841 lines deleted across two commits; the model decides the rest
Idle GPU costabout $1,000 a month0polling health check replaced with an on-demand one

One full pipeline run was scored the same way: 365 timeline entries assembled, 41 footage placements from a library of 148, of which 22 were right, five acceptable, seven the wrong location and three too long. Seven wrong out of forty-one is not a number most people would publish about their own system. It is the number that told me what to fix next.

The handover is the deliverable

An engagement that ends with a running system and no handover is not finished. The ten handoff documents from this engagement, across four codebases, all have the same shape, and the shape is closer to a contract than a memo.

  1. From, to, date, subject. Every one opens by saying whose problem it is and whose it is not: "nothing in this folder is application code", "no changes on your side", "not urgent". And who to come back to with questions.
  2. What shipped, with the commits. Each change named against the commit that made it, and the verification next to it: build green, lints clean, test suite at its baseline, no new failures.
  3. What was deliberately not built, and why. The event webhook was not built because the receiving route did not exist yet. The note says do not set the address, and holds the secret ready for when it does.
  4. What was ruled out, with reasons, so the next engineer does not reopen it. Adaptive streaming for eight-second clips: overkill. Removing the master render: too many consumers. Feature flags: out of scope, ship the clean cutover.
  5. The activation order, with the person named on every line. You hand the owner the DNS records. The owner adds them. You verify the domain. The owner sets two secrets and redeploys. The owner triggers one real event and you confirm it arrived. Step six, the one people tend to skip: re-issue the key, because the current one was pasted into a chat.
  6. Acceptance the other side can check. Every address in the sitemap answers with the same page. Every old redirect still redirects. A test object appears within a minute and disappears on delete. Performance 90 or above on mobile. No change to any analytics identifier.
  7. Open questions for the owner, asked rather than decided. Keep the two old posts or retire them? He said either is fine, so it is recorded as either. And a temporary overlap so nothing breaks during the switch: for a week the app wrote its pages to both the old folder and the new one, and the second copy was removed the day the owner confirmed.

Then I leave. The last document is a copy list, six files, take these and leave the rest, followed by "what is next, in order", where every step I cannot take names the person who can. The founder connects the search property. The founder creates the token. The founder approves the weekly schedule before it spends anything. The customer's own team can add a second brand to the shipped system without engineering, and the note shows how. The documentation keeps itself current after I leave, because an agent with a defined job regenerates it when the structure changes and is not allowed to create new documents.

The same model with a team

On a retail platform I led for nineteen months, a live merchandising operation with purchase orders, cost of goods, stock transfers between stores and integrations into the point of sale, the accounting system and the shipping carriers, the model was the same and the mechanics were different. Branches carried the release version rather than an issue number. Features merged into the version branch many times over a month before the version merged to main, and pull requests were used only at release time. Reverts were part of the day, not an incident: a change merged at 8:06, reverted at 8:09, fixed, merged again at 8:21 and released at 8:24. I owned the architecture, the split between the transactional store and the analytics store, the AI layer over the sales and stock data, and every integration with the systems the business already ran. A team of seven built on that. If you read the commit log of a real retail operation, most of it is reconciling other people's data: missing orders, stock counts that disagree. That reconciliation is the main part of the job, not a side task.

When this model does not fit

I sell this way of working, so read this section with that in mind. These are the cases where I would tell you not to hire me.

Common questions

What is the forward deployed engineering model?

An operating model in which an engineer builds inside the customer's business: with the customer's data, inside its systems, under its written rules, shipping something usable every week, and ending with a handover the customer's own team can execute. It differs from consulting in that the artifact is a running system, and from a product team in that the work is shaped by one company rather than many.

What happens in the first week?

Decisions, not code. The owner's decisions and operating rules go into a file the engineer treats as fixed. Then one small feature is taken through the whole build process end to end, so the pipeline is proven before anything large goes through it.

What ships each week?

Something the customer can use through a real channel. Progress nobody can see or use does not count. A week that produces nothing usable is explained in plain language, with what blocked it and who unblocks it.

How does one engineer keep the pace of a team without breaking things?

The compiler and the linters enforce the quality rules, so code that can panic, swallow an error or leave a placeholder cannot be committed. One task at a time, a commit after each, automated reviewers with narrow jobs, and a learnings file so a mistake is made once. Roughly 2,900 commits across 111 issues without a pull request, on one engagement.

How are credentials handled so they do not block?

Every external dependency has a real implementation and a deterministic stand-in, chosen by whether the secret is present. The whole system runs and tests before any customer account exists. When the keys arrive, one variable turns the real thing on.

What does the handover contain?

From, to and date; what shipped with the commits; what was deliberately not built and why; what was ruled out; a numbered activation order naming who does each step; open questions asked rather than decided; and any security action, such as re-issuing an exposed key.

When does the model not fit?

When the owner cannot decide weekly, when nobody inside will own the system, when the data cannot be read this week, when a strategy document is what is wanted, or when a product already does the job.

Cite this

Arun Prasath E G, "Forward deployed engineering: how an engagement works, week by week," apeg.dev, published 14 September 2026, updated 15 September 2026. https://apeg.dev/forward-deployed-engineer/how-it-runs/

Arun Prasath E G

Agentic AI architect. Twenty years in enterprise architecture, seven companies built and sold, more than 8,000 commits in the last twelve months across a retail platform, an ad-acquisition platform, a transactional email service, a video product, robotics and CPU inference research. Every number on this page comes from the engagement's own records.

Working with me

I take on one or two engagements at a time, inside the company, and I hand over when it runs. If you have a problem in your own processes that no single product solves, and you need it built and running, not just a recommendation, that is the kind of work I do.