The assistant lives in the database too
The usual way to add an assistant to a business application goes something like
this. Export the schema into a vector store. Write a document explaining the
domain to the model. Give it a database connection, then add a paragraph to the
prompt asking it politely never to run an UPDATE. Ship it, and watch the
support queue.
Two things are wrong with that, and they are the same two things wrong with the frontend-backend split we wrote about last time. The truth about the application now exists in two places, and one of them goes stale the moment someone edits a button. And the only thing standing between the model and your production data is a sentence written in English.
If the application already lives in the database, the assistant can live there too — and then its limits are enforced by the database engine instead of by a paragraph of instructions.
In TSQL.APP that assistant is ask_ai: a set of stored procedures, tables and
views inside the Solution's own project database, one per Solution. Not a service
running beside the app. There is no separate process to deploy, and nothing to
keep in sync.
Talking to her
Users reach her from a button in the app. But because she is just objects in a database, plain T-SQL is a first-class way in:
sqlEXEC dbo.sp_ask_ai N'How many cards does this application have?';
That is the whole interface — from SSMS, from sqlcmd, from an Agent job. It is
deliberately not a second implementation of the agent: the call posts to the
same Service Broker queue the app posts to, and everything downstream is the same
code a user gets in the chat modal. Same worker, same conversation history, same
tools, same fence. A test path that exercised a private copy would prove nothing.
What she can do from there is read: the catalog, the metadata that describes every
card, field and button, the body of any action script, and the business tables
themselves through SELECT. She can keep lessons about what she learns. And she
can write a button.
The obvious objection
Nobody sane wants a language model holding a connection to their production database. So it does not have one.
Every query she writes is executed impersonated as a dedicated login with
read-only rights, and DENY on the things she must never see — the API key
settings, the token tables, and the raw conversation table. She reads her own
threads through a view scoped to the caller, so one user's conversation cannot
surface in another's.
The interesting part is what happens when she needs to create something. She owns
exactly one schema, called ai, and has ALTER on nothing else. So when she
issues DDL, SQL Server refuses anything outside that schema on its own
authority. There is a string check in front of it as well, but its job is only
to give her a readable error message — if the check and the permission ever
disagree, the permission is right.
The fence is ownership, not parsing. That distinction matters, because a fence
made of string inspection is a fence you have to be cleverer than the caller to
maintain, forever. Ownership also has a useful second effect: it deliberately
breaks ownership chaining into dbo, so a view she creates cannot read anything
she could not have read directly.
Writing a button is fenced differently again, because an action script runs with the application's own rights — far more than hers. So that path is: refuse anything protected, snapshot the current version, write, compile-check the result, and automatically put the snapshot back if it does not compile. Every version is kept and restoring one is a tool she has. A failed write costs nothing and returns SQL Server's own error message, phrased as an instruction, and she is expected to fix it herself on the same turn.
And a button she wrote does nothing at all until a human presses it. Compiling is not the same as being correct, and we do not pretend otherwise.
The part that surprises people
Here is the mechanism most people do not guess, and it is the one that decides whether an assistant like this is still useful in a year.
Structure is read live. Meaning is stored.
Nothing about which cards, buttons and fields exist is ever copied into her memory. The tool that lets her explore an application reads the metadata tables straight off the live database, every time she asks. Same for object definitions, which come back with their immediate callers and callees attached, derived from the catalog at the moment of reading.
That is a deliberate refusal of the standard pattern. A stored copy of a schema is wrong as soon as someone adds a column, and it fails silently — the model answers confidently from the copy. Worse, a "mind map" of a database with a node per table and an edge per foreign key is not a mind map at all. It is a second, worse copy of something the catalog already holds perfectly.
So what does get stored is only the part no catalog can produce: what a screen is for, what this particular business calls a concept, which button actually does the job someone described in their own words. Her graph is meaning, and the procedure that writes relationships into it will actively refuse an edge the catalog could have derived itself.
The consequence is that her knowledge of your application cannot go stale, because she does not have any. She has a way of looking, and a store of what looking has taught her. Rename a column and she is not wrong — she is simply looking at the new name.
The same honesty applies to the limits of what the catalog knows. Action scripts are dynamic SQL, which dependency tracking cannot see, so her tooling reports "nothing static references this" rather than "nothing uses this". A tool that overstates its own certainty is how you get a confident, wrong answer.
Why build it this way
The design test we apply to every change is whether it lives in the structure or in the wording. Ownership, permissions, and what a tool deterministically returns hold no matter which model arrives next year. Tool descriptions and prompt phrasing are persuasion — useful, but the next model may simply ignore them.
Which sets the goal: make the harness good enough that even a modest model gives excellent answers. When results depend heavily on which model is behind it, that is a gap in the harness, not a problem with the model.
There is documentation and a programming reference online, and you can always book a demo.