Agentfy integration
Accepted direction · API merged · app implemented · local browser verified · 13 October 2026 · the shared integration contract written down and Shiffty brought to it (eighth field, chat switch, profile update in place) 15 October 2026 · verified against the local fake and a local Agentfy, nothing deployed · chat hidden in the app from 14 October 2026 and the local stand-in for Agentfy removed that day (the stand-in's tables dropped 16 October 2026) · chat shown again where the API says the assistant is available, and a store's agent connected from its page, built 19 October 2026, checked against a local Agentfy, not deployed · the owner's assistant — one agent per company, decided and built 20 October 2026, checked against a local Agentfy, not deployed · the company's assistant connected first, when a platform administrator approves the company, decided and built 23 October 2026, not deployed · the owner's assistant creates a store, built 23 October 2026, tested against an in-memory Agentfy, not deployed · a new profile reaches every company's agents by itself, decided and built 23 October 2026, checked against a local Agentfy, not deployed · why a company's assistant failed shown to the administrator, with Retry, and the owner a short text without codes, decided and built 28 October 2026, tested against an in-memory Agentfy, not deployed · the chat reads the new names of Agentfy's answer events (AGNT2-596), built 28 October 2026, tested against an in-memory Agentfy and checked against a local Agentfy, not deployed · the week a schedule card changes shown beside the chat, built 4 November 2026, tested against an in-memory Agentfy, not deployed · descriptions asked for before a week is built, in both assistants, built 5 November 2026, tested against an in-memory Agentfy, not checked with a live agent, not deployed
Each store would get its own agent on the Agentfy agent platform; the manager and the employees of that store would talk to it inside the Shiffty application, each as themselves, and never see Agentfy. Since 20 October 2026 the company's owner has one more agent of their own, for every store at once.
Agentfy runs the conversation; Shiffty keeps the facts, checks every permission and draws the chat.
How Shiffty maps onto Agentfy
Agentfy has three levels, not two:
Organization — Shiffty itself as a partner: namespace, credentials
└─ Team — one Shiffty company
└─ Agent × N — one per store
└─ Agent — the owner's, one per company (since 20 October 2026)
ExternalIdentity — an employee or a manager (externalUserId = Shiffty's employment id),
or the owner (externalUserId = the owner's user id)
Conversation — one per (agent, person)- One company is one team; one store is one agent.
- A store's manager and its employees talk to the same agent, each with their own identity. An employee or a manager has access to exactly one agent, because each person belongs to exactly one store (11 October 2026; until then a manager was to manage several). The owner talks to an agent of their own: see the owner's assistant.
- The agent for a store would be created by Shiffty when the store is created, through Agentfy's provisioning interface. This depends on Agentfy's operator; see what has to be true first. What is built (19 October 2026) also lets the owner or the store's managers start or retry it with Connect assistant on the store's page (Screens). In the built API, creating an active store already tries to set up its agent when Shiffty is connected to Agentfy; if that try fails, nothing else fails, and the store's page shows the agent as not ready, with Retry.
How these are recorded on Shiffty's side is on Data structure.
The owner's assistant
Decided by the owner on 20 October 2026; built the same day, tested against an in-memory Agentfy and checked once against a local Agentfy, not deployed. This replaces "no assistant for the owner" of 19 October 2026.
- One agent per company, not per store. It sits in the company's team in Agentfy next to the stores' agents. Its external id is the company's (team's) id; it has a profile of its own with its own revision, so changing the store agents' profile never touches it and the other way round.
- It makes the company's team in Agentfy (the owner's decision of 23 October 2026; until then it joined the team the first store's agent made, and connecting it before any store's was refused). Agentfy makes a company's team together with the first agent it is asked for. The company's assistant is now connected when a platform administrator approves the company, so it is that first agent, and every store's agent created afterwards joins its team; no store has to come first. Approving never waits long for Agentfy and never fails because of it: when Shiffty is not connected to Agentfy, or the setup fails, the owner sees Not connected or Failed with Retry on Stores. A company whose team a store's agent made earlier keeps that team: that store connects first and the company's assistant joins it. Tested against an in-memory Agentfy, including a failing and a slow one; not deployed.
- Why it failed is said (the owner's decision of 28 October 2026; built that day, tested against an in-memory Agentfy only, not deployed). A failed setup keeps what Agentfy answered — its code and HTTP status, never its text — as a short reason that says what to do, for example "Agentfy rejected Shiffty's key for this organization (CREDENTIAL_REJECTED, 401)", or that Agentfy did not answer in time, and the API writes one log line for it. The platform administrator sees it right after Approve and on the company's card under Requests, with a Retry that resumes the same setup and never makes a second agent; a company whose assistant was never made is listed as not set up, with Retry. The owner sees a short text instead — "The company assistant could not be set up. We have been notified; press Retry later." — with no codes and nothing only an administrator can do, on Stores and on their Assistant tab, with Retry there too; the full reason stays stored for the administrator. Until then the reason was a general "could not be confirmed" and the administrator saw only "approved".
- The owner talks to it as themselves, with their own identity — the owner's user id — and the role Agentfy calls owner. Shiffty never tells Agentfy that the owner left: Agentfy would then take the team's ownership away for good. A former owner's access simply runs out within minutes and is refused by Shiffty.
- With the owner's rights, over every store. Every store tool takes the store it works on; the owner names any store of the company, and a store left out is answered with the list of stores. The rights still come from the conversation's permission, never from the model; a store outside the company is not found. Every change is a card the owner confirms in the app, and the confirmation checks the rules again. Publishing a week exists only here, as a card (the tools).
- Connected like a store's. The owner connects it at the top of Stores (Company assistant: Not connected, Setting up, Ready or Failed, with Connect assistant or Retry), and the local start connects it first (after the stores until 23 October 2026). When a reset database lost its access key it says so and Retry gives the same agent a new key, as for a store. The owner can also retire it; the stores' agents stay.
- Each agent sees only its own tools. A store's agent still discovers exactly the tools and arguments it had; the owner's agent discovers the owner's.
- It can create a store (23 October 2026, built and tested against an in-memory Agentfy, not checked against a local Agentfy, not deployed). Confirming the card creates the store and then connects the store's assistant, as creating it in the app does; the store's assistant is connected only after the store is saved, because Agentfy checks its tools with the key Shiffty stored for it. Both profiles moved to a new revision that day (the owner's 5, the stores' 9): new tools, the product called Shiffty, and a plain answer with the place in Shiffty when no tool does what is asked. A local database reset after that change refuses the agents made before it, as described below.
- Both assistants ask for missing descriptions before they build a week (the owner's request of 5 November 2026; built that day, tested against an in-memory Agentfy, not checked with a live agent, not deployed). When the store, a position or a person the week would plan has no description, the solver's tool plans nothing and says what is missing; the assistant tells the person, asks for what the week needs, writes the answer into the descriptions with a card and builds once it is confirmed — or, only when the person says to build without it, builds and says what was missing. The owner's assistant has a card for a position's description too. Both profiles moved to a new revision (the stores' 15, the owner's 11). How it works is on The agent's tools.
Checked on 20 October 2026 in a working copy against a local Agentfy, as the demo owner: "what is short next week across stores?" was answered from the company overview; asking to plan Harbor Street's draft week gave a solver card that also planned the store manager's shifts, which, confirmed in the app's route, wrote 11 shifts and removed 6 in the draft without publishing it; a change to a manager's title and contract hours and a manager's description became cards, confirmed. One flaw was found and fixed the same day: a store tool called without its store failed the whole turn; it now answers with the list of stores. The cards were confirmed through the confirmation route, not by clicking in a browser. The copy then retired its five agents.
Two ways in, and why the widget is out
| Path | What the agent knows about the person | Tools | Verdict |
|---|---|---|---|
| Embed widget — Agentfy's ready-made chat placed on a page | Nothing: a visitor is anonymous to the agent | None | Not used |
| Partner server chat — Shiffty's API talks to Agentfy on the person's behalf | A permanent identity for each person | A trusted tool server run by Shiffty receives the person's context on every call | Chosen |
An assistant that cannot tell Anna from Ben cannot look up Anna's shifts or submit her request, so the widget is out.
With partner server chat the conversation is drawn by the Shiffty application, and the Shiffty API talks to Agentfy. In order: tell Agentfy the person is a member of the company's team → open a conversation with the store's agent → attach the person's context to it → send the message → read the answer as it is produced.
How a tool call is authorised
The agent would never be trusted to say who it is acting for.
- When Shiffty opens a conversation, it writes a grant: which employment, which store, which role, and until when. It binds the grant to that conversation.
- Agentfy sends the grant back on every tool call, in a header named
X-SD-Context, together with the identifiers of the agent, the conversation and the turn. - Shiffty's tool server checks three things before doing anything: the grant is still live, the store in it matches the agent that is calling, and the role in it allows this tool.
One agent per store serves both roles. The grant, not the agent, decides which tools are allowed: an employee's conversation cannot reach a manager's tool.
The tool server is an MCP server — MCP is an open standard for connecting agents to outside systems. This settles the question on Agent and solver: the tools reach the agent through one MCP server that Shiffty runs, and the solver stays an ordinary service behind it.
The tools the agent would get
| Tool | For whom | What it would do |
|---|---|---|
| Read my shifts | Employee, manager | The person's shifts in the published schedule |
| Check a change | Employee, manager | Whether a particular swap or day off breaks a rule |
| Find cover | Employee, manager | Who could take a shift without breaking a rule, and what it would cost |
| Explain a refusal | Employee, manager | Why something is not possible and what would fix it |
| Submit a change request | Employee | Hand the prepared change over to the colleague and then the manager |
Built in the API, not deployed, first as seven tools (13 October 2026): my_shifts, check_change, find_cover, explain_refusal, submit_change_request and request_status for managers and employees, and team_week — the store's week — for managers only. submit_change_request is the only one that leads to a change, and the change becomes a request only when the person confirms its card in the chat; the request still needs a decision. None of them drafts or changes a schedule. Since 19 October 2026 they are part of one catalog with nine more read tools — the day with its coverage, the month, duty gaps, a person's week, the store, its people, requests to decide, one request, "Waiting for you" — and a plan to let the assistant do, step by step, what the person can do in the app, except deciding requests and publishing weeks: see The agent's tools.
“Build a schedule” is a button in the application, not a tool of the agent. A tool call on Agentfy has a short time limit (below), and building a schedule for a real store may not fit inside it. The split of rights between the roles in the table is a proposal. What the solver does behind these tools is on Agent and solver.
What Agentfy does not do today, and what Shiffty therefore owns
The limits below were read from Agentfy's repository on 5 October 2026. The inline-profile contract was checked again on 13 October (AGNT2-476). That day SHIF-19 verified local provisioning → ready → chat → MCP tool call → done; hosted and production environments remain unverified. See the merged API implementation.
| Agentfy constraints (5 October; profile and local verification updated 13 October 2026) | What follows for Shiffty |
|---|---|
| Partner server chat completed a conversation with a tool call against local Agentfy on 13 October. | The API is merged. The app's chat was implemented on the SHIF-20 branch, hidden from 14 October 2026 and shown again since 19 October 2026 (below). Hosted/production interoperability is not yet verified. |
| Provisioning for an organization is switched on only in Agentfy's database, by its operator. | The operator has to enable it for the Shiffty organization before a store can get its agent automatically. |
| Agentfy accepts an inline agent profile under an organization policy approved by the operator (AGNT2-476); there are no agent templates. | Shiffty versions the name, instructions, skill and required tools in code as profileRevision and sends them in agent.profile. The policy limits models, MCP hosts, trusted context, worker tools and egress. |
| An agent cannot start a message: there are no outbound notifications. | Telling a person that something is waiting is Shiffty's job — the “waiting for you” list on Screens. |
| A tool call has 15 seconds. | Tools must answer quickly; building a schedule stays a button in the application. |
| A turn may make at most 3 data-changing tool calls. | One request from an employee has to fit in a few steps; Shiffty's tools are shaped for that. |
| Exactly one trusted MCP server per conversation. | All of Shiffty's tools sit behind one server. |
| No per-person memory across conversations in partner turns. | Shiffty keeps the state and hands the agent the facts every time. |
| Organization-paid usage billing is not production ready. | How Shiffty would pay for its stores' conversations is unsettled. |
Application chat
Shown again since 19 October 2026 (the owner's decision, for good), when the API says it is available; built, checked against a local Agentfy only, not deployed. The application asks the API on sign-in and when the tab is opened: GET /v1/me answers assistant with available, a reason in words and a code — not_connected (Shiffty has no Agentfy connection in the admin app's Settings), chat_off (no server chat key), agent_not_ready (this store's agent is not ready) or, since 20 October 2026, owner_agent_not_ready (the owner's own agent is not connected or not ready; until then the code owner said the owner had none), and none when it is available. Available, each role's Assistant tab is the chat below, and the "Ask the assistant" links elsewhere are shown. Not available, the tab says why in plain words and who can fix it — a platform administrator in Settings, or the store's manager or the owner on the store's page — and the links are hidden. When the owner's assistant is not ready, the owner's tab says so and, since 28 October 2026, shows the company assistant itself — its status, why a setup failed, and Connect assistant or Retry (above); until then it linked to Stores. A store's agent is shown and connected on the store's page: GET /v1/stores/:id/agent gives Not connected, Setting up, Ready or Failed with a safe reason, and profileUpdateError when the agent still runs on an older profile; Connect assistant or Retry calls POST /v1/stores/:id/agent (the owner and that store's managers). Setting up moves on only with a POST, so while it is setting up the page posts again every 3 seconds, at most 20 times. Since 19 October 2026 an agent is Ready only while Shiffty holds the access key it gave that agent: after a reset local database (same store ids, the agent still alive in Agentfy) the store shows Failed with that reason instead of Ready, and Connect assistant or Retry gives the same agent a new key; checked against a local Agentfy only. Also since 19 October 2026, after a local reseed nobody has to click: once the local API answers, the developer's start signs in as the demo owner and connects every active store the same way, always in the same order, and prints one line per store — Ready, or Failed with the reason; checked against a local Agentfy only. What it cannot do yet: when the agent's profile changed between its creation and the reset, Agentfy refuses the new request (it keeps the original one and offers no way to look an agent up by Shiffty's ids), so that store says Failed with that reason, and the agent has to be retired in Agentfy, losing its conversations, before it is connected again. See Screens.
From 14 to 19 October 2026 each role's Assistant tab said "Assistant · In development" and that, until it is ready, everything is done by hand in the other tabs, behind a constant in the app; the links that would open the assistant were hidden. That constant is gone. The scripted demo (11 October 2026), which answered a few fixed questions with canned replies, is removed from the code, and there is no scripted fallback: when the API answers that Agentfy is not configured, the app asks GET /v1/me again and shows the panel.
On the same day the API's local stand-in for Agentfy was removed — a mode (AGENTFY_INTEGRATION_MODE=fake) in which the API played Agentfy itself, with a short script instead of a model, and kept its conversations in five tables of its own; the migration 20261016T1038_drop_fake_agentfy (Prisma 8, 16 October 2026) drops those tables. Local runs now have the integration off. A leftover fake — in the environment or in a saved Settings row — is treated as off, with the reason shown in Settings and a warning in the API's log, and Settings no longer accept it. The real organization mode, the MCP server with its seven tools, the grants, the audit and the confirmation cards are unchanged. The API's automated tests check them in organization mode against an in-memory stand-in for Agentfy that lives in the tests only, where the test plays the model by calling the MCP server with the grant Shiffty bound to the conversation.
What follows describes the chat as it was implemented on the SHIF-20 branch and verified in the browser against local Agentfy on 13 October 2026, and checked again in a browser against a local Agentfy on 19 October 2026. Managers and employees see the store agent when the API reports that it is available; since 20 October 2026 the owner sees their own agent the same way.
The conversation loads from saved history. The app shows received text and tool states, without simulated progress. If a connection breaks, the reply stays unconfirmed and can be recovered with the same message. Schedules and requests remain available.
Agentfy renamed the events of an answer on 26 October 2026 (AGNT2-596): the text now arrives in pieces under new names, a tool's start and end are named differently, and there is no final message with the whole text. Shiffty did not know the new names, so from then every answer ended with "The run could not be confirmed", although Agentfy had finished it. Since 28 October 2026 the API reads both the old and the new names, puts the whole text together from the pieces, skips any event it does not know instead of failing, and writes one line in its log, without the conversation's content, when an answer's stream breaks. Built, tested against an in-memory Agentfy speaking both, checked against a local Agentfy on 28 October 2026 (an employee's answer and the owner's store card); not deployed. The names are in api/AGENTFY.md.
A checked change appears as a confirmation card with the backend's description. Send request submits it for the colleague and decision maker; it does not change the schedule. Cards survive reloads, and retrying a confirmation recovers the same request. No saves the refusal for that card. Since 4 November 2026 a card that changes a week (create_week, change_week, solve_week) also has Show week: the week opens beside the chat with the card's changes on it — tried with every rule and thrown away, so it is what confirming would write — and after confirming, the week as saved (screen 13).
Operator settings
Built on the SHIF-23 branch, 14 October 2026; the eighth field added 15 October 2026; verified against the local fake, not against a hosted Agentfy and not deployed. The connection no longer lives in environment variables but in one Setting row (agent/agentfy) that a platform administrator edits on Settings, in the admin app — an application of its own next to the API and the app since 18 October 2026 (SHIF-36), built and not deployed; until then Settings were a section of the application. The fields, in the order every Agentfy-connected project shares: mode (off, fake, organization), API URL, organization ID, environment (test or production), provisioning key, server chat key, MCP URL, model. The exact names, types and environment variables are in the contract below. The two keys are stored sealed (AES-256-GCM under a key kept outside the database) and are never shown again — a read says only whether one is set, and a blank field on save keeps it. Saves are atomic and refused when someone else saved first; changing the organization, environment, origin or mode needs an explicit reconnect, which discards the previous connection's agents, teams and conversations so their ids are never reused. "Test connection" checks the API, the two permissions and the MCP URL separately and does not claim the end-to-end scenario, which only a provisioned store proves. Who changed which fields is recorded by name, never by value. Every running API picks a change up within 15 seconds. Import of the old environment variables is an explicit action. See api/AGENTFY.md in the repository for the mechanism.
Agentfy integration contract
Four products connect to Agentfy the same way — Bonsite, Securify, Shiffty and Store Deputy — and Shiffty is the reference the other three are being brought to. This section is the contract they share, written down so that a ticket in any of the four can point at it. Where this text and Shiffty's code disagree, the text is right and Shiffty is corrected (SHIF-24 did that on 15 October 2026); the siblings follow in their own tickets of the same series.
One settings group with the same eight fields, one settings engine, one way to read the connection, one MCP skeleton, one profile shape. A product may differ only in its tools, its agent's text and its own provisioning and chat screens.
The eight fields of agent/agentfy
Exactly these, in this order, with these names, types and environment variables. The definition format is the one in Shiffty's api/src/slices/setup/agentfy/setting/agentfySetting.ts: a field has name, label, type (string, url, enum or secret), options, default, required, placeholder, help, env; the group has title, description, fields, reconnectFields (mode, apiUrl, organizationId, environment), validate(data, {production}) returning {field: problem}, and fromEnv(env).
| # | Field | Type | Default | Environment variable | Rule |
|---|---|---|---|---|---|
| 1 | mode | enum off · organization | off | AGENTFY_INTEGRATION_MODE | Shiffty: a leftover fake is off and cannot be saved (since 14 October 2026) |
| 2 | apiUrl | url | — | AGENTFY_URL | the origin only — no path, query, fragment or credentials; HTTPS, plain HTTP only for loopback outside production |
| 3 | organizationId | string | — | AGENTFY_ORG_ID | A-Za-z0-9._:-, 1 to 128 characters |
| 4 | environment | enum test · production | test | AGENTFY_ORG_ENVIRONMENT | must match the credentials' environment |
| 5 | provisioningKey | secret | — | AGENTFY_ORG_KEY | orgk_… |
| 6 | serverChatKey | secret | — | AGENTFY_CHAT_KEY | orgk_…, different from provisioningKey; present means chat is on, empty means chat is off; not required in organization |
| 7 | mcpUrl | url | — | MCP_PUBLIC_URL | the exact public address of this API's POST /mcp; required in organization |
| 8 | modelId | string | empty | AGENTFY_MODEL_ID | empty means the first model the organization policy allows; sent as profile.modelId when provisioning |
validate is the same everywhere: in organization the fields apiUrl, mcpUrl, organizationId, environment and provisioningKey are required, serverChatKey is optional but, when set, must be orgk_… and differ from provisioningKey; apiUrl carries no path, query, fragment or credentials. The old names — AGENTFY_MODE, AGENTFY_API_URL, AGENTFY_ENVIRONMENT, AGENTFY_PROVISIONING_KEY, AGENTFY_SERVER_CHAT_KEY, AGENTFY_MCP_URL, AGENTFY_CHAT_ENABLED, AGENTFY_TEMPLATE_* and the legacy/live modes — are read nowhere, and .env.example and the docs no longer mention them as live. Until 14 October 2026 the contract also had a fake mode (an in-API stand-in for development, refused in production, needing only mcpUrl); Shiffty removed it on the owner's decision, and whether the other three products drop it too is for their own tickets.
The settings engine
One slice, setup/setting, as in Shiffty, that knows nothing about Agentfy. A Setting row holds scope, scopeKey, group, code, version, data, source (database or env), enabled, lastCheck, lastCheckAt, updatedAt, updatedBy. Secrets are sealed under SETTINGS_KEY (a secret box; resealed at startup after a rotation with SETTINGS_KEY_PREVIOUS), saves are atomic under an optimistic version, every change is audited by actor, action and field names, and the API reads a typed snapshot. Group definitions are handed in with SettingModule.forRoot([...]).
One place to read the connection
setup/agentfy/connection.ts exports the type IAgentfyConnection — mode, source (database, env or none), reason, refused, apiUrl, organizationId, environment, provisioningKey, serverChatKey, mcpUrl, modelId — and the function currentConnection(). Nothing else reads process.env.AGENTFY_* or keeps its own copy: no per-request storage wrappers, no injected snapshots, no settingValue(). Everything goes through currentConnection().
REST for administrators
For a platform administrator, not a team owner; generic by group and code:
| Route | What it does |
|---|---|
GET /settings | every group with its fields (a secret shows only hasValue), source, version, enabled, state, lastCheck, importable |
GET /settings/:group/:code | one group in the same shape |
PUT /settings/:group/:code | body {version, data: {field: string | {op: 'keep' | 'replace' | 'clear', value?}}, source?, enabled?, reconnect?}; 400 with fields when a value is refused, 409 SETTING_VERSION_CONFLICT or SETTING_RECONNECT_REQUIRED, 503 SETTINGS_KEY_MISSING |
POST /settings/:group/:code/import | body {version}: imports the environment variables, values are not returned |
POST /settings/:group/:code/test | the check result below; it creates no agents and runs no model unless a separate, explicit button does |
POST /settings/:group/:code/reconnect | {removed, setting} |
GET /settings/:group/:code/audit | who changed which fields, never values |
POST /settings/rotate | optional, the only route outside group/code: reseal every secret under the current SETTINGS_KEY after a rotation; if a product has it, it is exactly this |
The response types are Shiffty's admin/slices/setting/domain/setting.types.ts: ISetting, ISettingField, ISettingCheck, ISaveSetting, and SecretOperation with the key op.
The shape of a test result
{
"at": "2026-10-15T09:00:00.000Z",
"mode": "organization",
"ok": true,
"checks": {
"api": { "status": "ok", "detail": "…" },
"provisioning": { "status": "ok", "detail": "…" },
"chat": { "status": "skipped", "detail": "…" },
"mcp": { "status": "ok", "detail": "…" },
"mcpEndToEnd": { "status": "skipped", "detail": "…" }
},
"note": "…"
}Each check is ok, failed or skipped with a human-readable detail. The five aspects are told apart and never pass a network answer off as the whole scenario: MCP end to end is proven only by a provisioned store.
The admin interface
One setting slice: a store with fetchSettings, saveSetting, importSetting, testSetting, reconnectSetting, fetchAudit; one generic group card that renders the fields the registry declares (Shiffty's admin/slices/setting/components/setting/group/Card.vue); CHECK_LABELS for the five aspects. No hard-coded path to one group and no login of its own in the store.
One MCP skeleton
POST /mcp, Streamable HTTP, stateless. The bearer token is the agent's credential; the conversation grant travels in the header X-SD-Context. No or wrong credentials: 401 with WWW-Authenticate: Bearer. Any other method: 405. A JSON-RPC batch: 400. The slices are mcp/server, mcp/policy, mcp/grant and mcp/credential. Only the table of tools and the call policy differ between products. The fake mode lives in setup/agentfy/fake and calls the same /mcp.
The agent profile
One type, IAgentfyProfile: {name, instructions, skill: {name, description, body}, modelId?, mcp: {url, requiredTools, trustedContext: true}}, in agent/<product>Provision/domain/<product>Profile.ts next to PROFILE_REVISION and REQUIRED_TOOLS (in Shiffty: agent/orgProvision/domain/storeAgentProfile.ts). Provisioning freezes the profile into the intent. When PROFILE_REVISION is raised, the profile is updated in place through Agentfy's PUT /v1/orgs/{org}/operations/{operationId}/profile {expectedVersion, profile} (AGNT2-477), without recreating the agent; profileRevision is kept in the intent, and a failed update is shown as profileUpdateError by GET /stores/:id/agent while the agent keeps its previous profile. modelId comes from the setting.
Every company's agents, not only the demo's (owner's decision, 23 October 2026). Until then an agent took a new profile only when someone ran its provisioning, so a company nobody touched stayed on the old one (on 23 October 2026 a real company's assistant stayed on owner revision 4 after revision 5 shipped, and kept saying it could not create a store). Now Shiffty's API rolls the profile out itself: about 10 seconds after it starts and then once an hour, it finds every ready agent on an older revision, of a company that is approved and active and of an active store, and updates it in place, one at a time, under the same company lease a person's Connect uses. It never creates, adopts or retires an agent. A refused update is recorded as profileUpdateError and tried again on the next run; the agent keeps working on its old profile. In the admin app, an approved company's card under Requests lists its assistants with their profile revision against the current one, the last error, and Update now. A local working copy does this only with AGENTS_CONNECT=1, as with connecting the demo's agents. Tested against an in-memory Agentfy and checked once against a local one; not deployed.
What may differ between products
Only these: the set of MCP tools and their call policy; the text of the agent profile (name, instructions, skill); provisioning and chat as product slices. Everything above is the same.
Done means
A ticket of this series is done when: the registry has the eight fields with the names and environment variables of the table, literally; a search for the old names finds nothing; GET /settings returns agent/agentfy in the shape above; the admin form saves, imports and tests through the generic routes; POST /mcp answers as described; provisioning and chat pass end to end locally in fake mode; and in organization mode against a local Agentfy provisioning reaches ready and the assistant answers in chat. The report opens with an explanation for someone who has not opened the repository, lists the checks that were run with their results, and says what was not verified.
Not decided
- Which language model to use in production. The
modelIdsetting (empty by default) names one within the approved policy; empty leaves the choice to Agentfy's first allowed model. Shiffty leaves it empty. - What the agent is told about a store at the start of a conversation, and what it must always look up.
- Whether the demo planned for 18 October uses Agentfy at all. The plan is unchanged by this page.
Where to go next
- The agent's tools: the catalog, its levels and the plan.
- Agent and solver: what counts the schedule behind the tools.
- Data structure: where the agent, the conversations and the grants are recorded.
- Screens: the two assistant screens, 13 and 16, and what the Assistant tab shows today.
- Open questions: what is decided and what is not.