JONAS STAMM
— FIELD NOTES
technical-deep-diveAugust 20, 2026· 7 min read

What Bau Enterprises Actually Made Us Build

Most of what we shipped on BauGPT in the last weeks had nothing to do with the model. It was folders, permissions, single sign-on, and Word files that open corr...

JS
Jonas Stamm
Founder, BauGPT

Most of what we shipped on BauGPT in the last weeks had nothing to do with the model. It was folders, permissions, single sign-on, and Word files that open correctly on a Bauleiter's laptop. The interesting AI part of a feature is usually done in an afternoon. The part that decides whether a construction company rolls you out across the whole Firma is who can see what, and almost none of it demos well.

The tenant boundary is the product

If a buyer asked me to name the single most important thing we changed, it would be this: the assistant stopped taking the company identifier that a client sent along with a request at face value, and started resolving file access on the server instead, while still being allowed to open a user's own private documents. Those two halves have to ship together. If you only harden the boundary, you break every private document. If you only open up personal files, you have a tenant boundary that a request body can talk its way past.

On top of that we added write protection on folders, so only the person who owns one and the admins can put anything into it. In Bau terms, that is the folder holding the Leistungsverzeichnis or the signed Nachtrag, the one where a well-meaning colleague dropping in a second version is worse than no version at all. And a refused write now comes back with the actual reason behind it, not a generic failure. That sounds like a small thing. It is the difference between a Poliere trusting the tool and a Poliere emailing the file to himself.

We also gave project teams a shared place for chats at company level, with an explicit matrix of who is allowed to do what, so a team works in one workspace instead of a chain of forwarded links.

ASIDE

Half of an enterprise integration is documentation, not code. Our steps for resolving a customer's Active Directory now spell out where an application-level Graph permission is required and where a delegated one is enough. In my experience that single distinction causes more confusion on an onboarding call than anything about the model.

None of this is model work. All of it is the answer to the question that every IT lead at a mid-size Bauunternehmen asks in minute ten of the first call.

The output is a Word file, not a chat bubble

Construction does not run on chat. It runs on documents that get printed, signed, stamped, and dragged into a project folder. So a lot of our recent work went into what comes out the other end.

Wide tables were the worst offender. A Bau table with positions, quantities, unit prices and remarks does not fit a portrait page, and the old behaviour turned the entire document sideways to make room. Now only the wide table gets its own rotated section, and the rest of the document stays upright. We also fixed line-break rendering in the office editor, stopped the model producing ASCII art in generated files, and killed a bug where table headers were written twice.

Then there is the German language itself. Umlauts and ß are multi-byte characters, and any string handling that counts bytes instead of characters will eventually cut one in half. We made the document pipeline pass UTF-8 explicitly when measuring and slicing text, and made a generated filename get cut only at a full character, never in the middle of one. A file called Baustellenbericht_Grünstra with a broken byte on the end is the kind of detail that makes an enterprise buyer quietly downgrade their opinion of everything else you built.

The nicest piece of this block: per-user Word templates, where a customer uploads their own .docx with placeholders and the model fills them in. Every Bau company has its own Briefkopf, its own Nachtrag form, its own Bautagebuch layout. Nobody wants our formatting. They want theirs, filled in correctly.

Onboarding is where trust is won or lost

When a construction group onboards, they do not sign up user by user. Someone hands over a directory and a few hundred people exist in your system by tomorrow morning. We found that those bulk-imported people showed up without a personal folder of their own, and without the onboarding record a normal signup gets, so their first experience was subtly broken. Fixed. We also stopped an SSO edge case from crashing outright: when someone signs in on a personal path and that address already belongs to an account, they now get an error they can act on.

The lifecycle-messaging side was a whole cluster of its own. Accounts that arrive through a directory sync never asked for anything, so replaying them into a welcome drip is embarrassing at best and a GDPR conversation at worst. We made sure that never happens. Around that we fixed the order of identify and alias calls so merges stop getting dropped, added detection and repair for identify calls that silently vanish, stopped a monitoring canary from writing its own output into nowhere, and made an open-ended backfill window raise a warning instead of quietly running unbounded.

That last group is a good example of a general rule. Silent failures in an enterprise account do not stay silent, they just surface three weeks later in front of the customer. The boundary has to be legible to the person on the other side of it.

"The boundary has to be legible to the person on the other side of it."

The plumbing nobody sees

A few of the changes were pure infrastructure, and they still ended up mattering to the customer experience.

We reordered the system prompt so the stable text sits ahead of the per-user memory blocks, and made every user's request start from the same cached prefix. Prompt caching only works if the identical part comes first, so this is one of those changes where correct ordering is the entire feature. We also kept the connection open while the model is thinking for a long stretch, so a slow reasoning pass no longer looks like a dead request. On the observability side, generation spans now carry the company identifier, which means we can actually answer "how is this account doing" instead of guessing from aggregate charts.

Two more worth naming. The assistant was giving people the wrong picture of what it could do, which is a fast way to lose a first-time user, so we fixed the prompt. And our document layout eval suite was breaking the CI guard step, so it got its own database and now runs clean. If your document output is your product, your document tests have to be the ones you never let go red.

We also finally landed project-level context that had been sitting half-finished: a project now carries its own brief, its own memory tier, and pinned material. And a migration that was not safe to re-run is now idempotent, which is the kind of thing you fix once and never think about again, right up until a deploy retries.

Do

  • Resolve tenant identity on the server, always.
  • Tell the user why a write was refused.
  • Give imported users the same setup as signups.
  • Test exports in the customer's real editor.
  • Treat string handling as a German-language problem.

Don't

  • Trust a company id the client sent you.
  • Fail a write with a generic error.
  • Assume bulk import is just rows in a table.
  • Assume valid markdown means a valid document.
  • Assume byte offsets are safe on umlauts.

If I zoom out on the whole stretch, the pattern is obvious. The AI capability was never the blocker. The blockers were a company identifier we should not have trusted, a folder anyone could write into, a table that rotated the wrong thing, a filename cut through the middle of an umlaut, and a few hundred directory-synced people about to receive a welcome email they never asked for.

That is the actual shape of enterprise AI in construction. You earn the right to be interesting by first being boring in all the places where a Bau company would otherwise get burned. Happy to go deeper on any of these if you are building something similar, just ping me.

— END · Field Notes —

Keep reading

All writing →
technical-deep-dive · Aug 31, 2026
01

The hard part of a tender radar is not the matching

Most of the work in shipping BauGPT's Ausschreibungs-Radar had nothing to do with matching. Deciding whether a public tender fits a Bau company's profile was th...

7 MIN READ
technical-deep-dive · Aug 24, 2026
02

The hard part of a tender radar is not the matching

Most of the work in shipping BauGPT's tender radar had nothing to do with matching. Matching worked early and was never the risky part. Everything after that wa...

7 MIN READ
technical-deep-dive · Aug 20, 2026
03

Wide tables, umlauts, and who is allowed to write into a folder

If you want to know whether an AI product is really running inside a construction company, don't ask about the model. Ask what broke last week. For us the answe...

7 MIN READ
— THE NEWSLETTER

One note a week.
No fluff, just what works.

AI engineering, growth hacks, and messy lessons from shipping BauGPT. Unsubscribe anytime. I'll even miss you.

FIELD NOTES · NEXT ISSUE DROPS MONDAY
↳ No spam. One note weekly.