tensquads — What we build
· Moe Ghashim
Read this page from the top. Each part uses the ideas of the parts before it.
Contents
How tensquads works. What the product is, with one picture and one example.
Words we use. The meaning of each important word.
The bots and the persons. The five bots of the MVP, and the role of each person.
How Petra works. How Petra makes decisions and reads the business.
How the owner speaks to Petra. The chat, email and WhatsApp.
How a bot does a task. The bot, the image, the sandbox and the state.
Credits and prices. The packages, the price of each task, and the cost.
What the squad remembers and learns. The memory, the trails and the learning.
How we build it. The rules for the code and the tools.
Feature list. All the features of the MVP, with the priority and the person who added each one.
Decisions. The questions that have an answer.
Test cases. The success cases for each bot.
Research and sources. What each reference says.
Open questions. The questions that have no answer.
1. How tensquads works #
tensquads gives a small business a squad of bots. The bots do the work for the business. The owner speaks to one bot only. Its name is Petra. Petra gives the tasks to the other bots, and the owner sees the result.
A company can launch with us: research the competition, build the website, and add support when there is a need for it.
Each bot completes its task and gives the result to Petra. Only Petra sends messages to the owner.
One request, in sequence
The owner makes a request. Example: "Build my website."
Petra selects the bot. In this example, Petra selects Angkor. For an automatic event, such as a new Google review, a fixed rule selects the bot.
The system does a check of the credit balance. If the balance is not sufficient, the system tells the owner to pay or to upgrade.
The bot does the task on Cloudflare. It uses an isolated sandbox only for a tool that needs a real computer. The bot cannot send a message to the owner. The bot cannot give the task to a different bot.
An action with a risk does not start without approval. If an action publishes, pays or refunds above the limits of the owner, the owner must approve it first.
Petra gives a report. Petra shows the result, for example a preview link. Petra also tells the owner which work remains.
The squad keeps a record. The system records each step. The squad keeps the knowledge for the next task.
2. Words we use #
Read these words first. All the parts below use them.
| Word | Meaning |
|---|---|
| Owner | The person who has the business and the account |
| Customer | A person who buys from the business of the owner. A customer speaks to Kyoto, not to Petra |
| Bot | One member of the squad, with one job. Also called a squadmate |
| Petra | The master bot. The only one that talks to the owner |
| Task | One piece of work given to one bot |
| Credit | The unit an account spends to run a task |
| Approval | The owner's yes to an action outside their limits |
| Trail | The full record of one task |
| Fixed rule | An instruction that sends one kind of automatic event to one bot |
| Price | The credits that the owner pays for one task. The price is fixed for each type of task |
| Cost | The money that one task costs us |
| Price list | The list of the prices for all the types of task |
| Sandbox | An isolated space where the tools of one bot run for one task. It starts from the image of the bot when a tool needs it, and it stops when the task is complete |
| Loop | The code that runs a bot for one task. It asks the model, runs the tools, and repeats until the task is complete. It runs outside the sandbox and keeps no state |
| Session | The full record of one task, in the database. The loop reads it to continue a task. It is the same record as the trail |
3. The bots and the persons #
Each bot is a character. The name of each character comes from a famous place. Refer to 10squads.com/design/#mascots.
From left to right: Petra, Machu, Angkor, Kyoto and Greenwich.
| Bot | Role | Does | Does not do | Speaks to | Example |
|---|---|---|---|---|---|
| Petra | Master | Selects the bot for each task. Asks the owner for approval. Gives the report. Reads the signals and suggests changes | The work of a different bot | The owner | "Your website preview is ready. Do you want to publish it?" |
| Machu | Researcher | Finds the competitors, reads their pages, and compares their offers and prices | A change to something that the public sees | Petra only | "Five restaurants are near you. Three have a lower price at lunch." |
| Angkor | Website and menu builder | Makes one landing page. A restaurant gets a menu. A grocer gets a list of items. Does the audit of the website | Publish without approval | Petra only | A preview link in the chat |
| Kyoto | Support | Answers the messages of the customers of the business. Makes refunds that are in the limits of the owner | Answer a review on Google Maps | The customers of the business, and Petra | A customer asks for a refund of $15 |
| Greenwich | Google Maps | Keeps the Google Maps listing correct. Answers the reviews. Reports the numbers of the listing | Answer a direct message from a customer | The public on Google Maps, and Petra | "A 2-star review came. Here is a draft reply." |
The MVP has these five bots. The roadmap bots (Analytics, Accounting, Finance) and the future squads come after the MVP. The success cases of each bot are in Part 12.
Roles #
Each bot has one role. The role tells you what the bot does, what it does not do, and to whom it speaks. The roles of the bots are in the table of the bots above. The persons also have roles:
| Person | Role | Can do |
|---|---|---|
| Owner | The person who has the business and the account | Speaks to Petra. Sets the rules. Approves actions. Reads and corrects the memory |
| Customer of the business | A person who buys from the business | Writes to the business. Kyoto answers |
| Super admin | A person of the tensquads team | Sees all the accounts, the trails, and the price and cost dashboard. Changes the prices |
4. How Petra works #
Petra receives each request and each event. This part shows how she decides what to do, how she reads the performance of the business, and how a fast model helps her.
How Petra decides #
Petra makes a decision for each request and each event. She does it in a fixed sequence of questions. Three parts of the system give the answers, and the owner gives the answer when the three parts cannot.
Routing sends each task to the correct bot. A message from the owner always goes to Petra, and Petra selects the bot. An automatic event, such as a new Google review, obeys a fixed rule if one applies. If no fixed rule applies, the event goes to Petra. The system does not give a task to a different bot without a report. If the bot is not available, the system tries again. If the task still fails, Petra tells the owner.
| Who answers | What it answers | Example |
|---|---|---|
| The code | A question that has a number or a rule | Is $60 above the limit of $20? Are the credits sufficient? Are there three complaints in one week? |
| Jev | A small question about the meaning of a text | Is this a refund request? Is this complaint about the same problem? |
| The large model | A plan, or a text | Which bots, and in which sequence? What does Petra say to the owner? |
| The owner | A question about the limits, the preferences, or a thing that Petra is not sure about | Do you approve this refund? Which instruction is correct? |
The sequence of questions
| Step | Question | If the answer is no | Test case |
|---|---|---|---|
| 1 | Is the request clear? | Petra asks the owner one question. No bot starts | P2 |
| 2 | Can a bot in the squad do this? | Petra tells the owner that no bot can do it. No task starts | J3 |
| 3 | Does the request agree with the preferences of the owner? | Petra tells the owner about the disagreement and asks which is correct | J4 |
| 4 | Does a fixed rule select the bot? | Petra selects the bot and gives the reason. If the task needs two bots, she tells the owner the sequence first | J1, J2 |
| 5 | Are the credits sufficient? | The task does not start. Petra shows a payment card | D5 |
| 6 | Is the action in the limits of the owner? | Petra shows an approval card. The action does not start until the owner approves it | D3 |
| 7 | Is Petra sure? | Petra asks the owner. She does not guess | J6 |
| 8 | Is this a signal, and not one event? | Petra records the event and makes no suggestion | J8 |
If all the answers are yes, the bot does the task, and Petra gives the report.
The rules for each decision
Petra records each decision in the trail, with its reason.
When the owner asks "Why?", Petra gives the reason in simple words. The reason agrees with the trail.
Petra cannot increase her own limits. If the owner asks for more freedom for Petra, that is a change to a rule, and the owner must confirm it.
When a number or a rule can give the answer, the code decides, not the model.
Rules and approvals. The owner sets the limits. Example: "Refund without my approval below $20." In the limits, the bot does the action. Out of the limits, Petra asks the owner, and the action does not start until the owner approves it. The system cannot increase its own limits. It can only recommend a change.
For the builders. These rules make the routing safe:
A message from the owner always goes to Petra. For each other event, a table of fixed rules in the database gives the bot. The most specific rule applies.
If no fixed rule applies, Petra selects the bot from a list of what each bot can do. The system records the selection and its reason.
The system does not change the bot silently. If no bot is correct, or the bot is not available, the task waits and the system tries again. Then the task goes back to Petra, and Petra asks the owner.
A bot does not give its task to a different bot, and it does not send a message to the owner.
Two bots can send messages to each other only if a list permits that pair.
Each account is isolated. Each query has the id of the account. Each bot has its own memory area and its own list of permitted tools.
The loop of Petra
Petra is always on, and she does not work in a sandbox. She uses the same loop design. For Petra, each bot is a tool: she starts a bot and gets only its last result, not all its turns. Thus the context of Petra stays small. For each message or event, she does this sequence:
She reads the state of the account from the database.
She makes the decision, with the sequence of questions in Part 4.
She answers the owner, starts a bot, or asks the owner for an approval.
She writes the state to the database, and she waits for the next message or event.
Performance review and suggestions by Petra #
Petra reads the performance of the business at regular intervals. She then suggests changes that can improve it. A change can be to the website, to the Google Maps listing, to the support answers, or to a different area of the business. Petra does not make a change without the approval of the owner.
Signals, not single events. Petra does not react to each piece of information. One complaint is an event. A bot answers it, and Petra records it. Petra makes a suggestion to the owner only when the event becomes a signal. An event becomes a signal in one of two ways:
A measurement confirms it. If a problem can be measured, Petra starts an audit. She makes a suggestion only if the audit finds the problem.
It occurs again. If a problem cannot be measured, Petra counts the events of the same type. Three events or more in one week are a signal.
The picture shows the two ways.
| Example | The event | What the bot does | What Petra does |
|---|---|---|---|
| The website | A customer says that the website does not respond | Kyoto answers the customer | Petra starts an audit of the website. If the audit finds that the website is slow, Petra suggests changes to the owner. If the website is not slow, Petra makes no suggestion |
| A bad review | A customer writes on Google Maps that the food came after more than 45 minutes | Greenwich answers the review | Petra records the complaint. After three complaints or more of the same type in one week, Petra tells the owner and suggests a change |
Jev helps here also. For each new complaint, the code asks Jev: "Is this complaint about the same problem as these earlier complaints?"
How Angkor does the audit of the website. This is a proposal.
Petra gives Angkor the task "audit the website".
The loop of Angkor asks for a browser. The system starts a sandbox, and the sandbox opens the website in a real browser, as a customer does.
Angkor measures the website five times: on a computer and on a phone. It records the time to load, the size of the page, and each error.
Angkor compares the numbers with the limits. Example of a limit: the page loads in less than 3 seconds.
Angkor gives Petra a report: the numbers, the cause of the problem if it found one, and the change that it recommends.
If all the numbers are in the limits, the report says "no problem found", and Petra makes no suggestion.
Where the data comes from
| Source | Data | Bot |
|---|---|---|
| The website | Visits, and what the visitors select | Angkor |
| Google Maps | Views, calls, requests for directions, reviews | Greenwich |
| Support | The questions and the complaints of the customers | Kyoto |
| Competitors | Their prices and their offers | Machu |
Sales and orders are not in the MVP, because no bot reads them. The roadmap bots (Analytics, Accounting, Finance) can add them later.
The sequence
Each week, Petra collects the data from the four sources.
Petra finds what changed. Example: "Calls from Google Maps decreased by 30%."
The large model writes possible suggestions. Example: "Add the lunch menu to the Google Maps listing."
Jev gives an answer to small questions about each suggestion.
The code uses the answers of Jev to remove the weak suggestions and to put the others in sequence.
Petra shows the owner a maximum of three suggestions. Each one shows the evidence and the price in credits.
The owner approves or rejects each suggestion. An approved suggestion becomes a task for a bot.
After some weeks, Petra measures the result and records it in the memory.
How we use Jev here
Jev does not write suggestions. It answers many small questions quickly and at a low cost. This feature has many such questions, so it is a good use of Jev.
| Question for Jev | Type of answer |
|---|---|
| Is this change in the data important, or is it usual? | Yes or no |
| Does the evidence support this suggestion? | Yes or no |
| Does this suggestion disagree with a preference of the owner? | Yes or no |
| How large is the possible effect? | A score |
| How much work is it for the owner? | A score |
| Which bot does this task? | One of the bots |
| Did the owner reject a similar suggestion before? | Yes or no |
The rules
Each suggestion shows its evidence, with a number.
Petra shows three suggestions or fewer for each week. The owner has little time.
If the owner rejects a suggestion, Petra does not make the same suggestion again.
If a suggestion did not improve the result, Petra records that, and she gives less weight to similar suggestions.
Fast decision model (Jev) #
Jev is a small, fast model with a low cost. It answers only two types of question: "yes or no?" and "which one?". The bots make many such decisions each day. We use Jev. We can test Sage, a model from a different company, later. The plan has three steps:
Build with the large model.
Record each decision.
Test Jev with those records, and change one use at a time.
The problem that Jev solves. Each task has small decisions. Which bot gets this task? Is this refund in the rules of the owner? Is this reply safe to send? Without Jev, the large model answers each of these questions. That takes seconds and costs more for each call.
An example. Sara has a grocery shop and uses tensquads. She has this rule: "Refund without my approval below $20, if the item was damaged or missing."
A customer writes to the shop: "My eggs arrived broken. I want my $15 back."
Kyoto must find if this message obeys the rule of Sara. This needs three small decisions. Jev reads the message and answers three questions:
| Question | Jev's answer | How sure |
|---|---|---|
| Is this person asking for a refund? | Yes | 97% |
| Is the reason "damaged or missing"? | Yes | 94% |
| Is the message abusive? | No | 99% |
Jev does not know the limit of Sara, and Jev does not make the decision. Our code makes the decision from the rule of Sara and the answers of Jev:
Jev is sure about all three answers, and $15 is below $20. Kyoto refunds the $15 and tells the customer. Petra does not interrupt Sara.
Jev is not fully sure. Example: 70% that the reason is "damaged". The refund waits. Petra asks Sara: "A customer wants $15 back for broken eggs. Do you approve?"
Jev is not sure. Example: the message is "this order was bad". Kyoto does nothing with money. Petra sends the message to Sara.
If the customer asks for $60, the answer is always "ask Sara", because $60 is above her limit. Our code does this check with a simple calculation.
Why we divide the work this way. A model is good at reading a message and finding its meaning. Code applies a money limit exactly, and we can test it. Thus the model reads, and the code applies the rule. The percentages in this example are not real. Moe sets the level at which Jev is "sure".
Where we use Jev
| Use | The question | If it is wrong |
|---|---|---|
| Routing | Which bot should take this task? | Low harm. Petra sends it again |
| Checking work | Does this result do what the task asked? | Medium. Poor work reaches the owner |
| Guardrails | Is this message safe to send? | Medium to high. A bad reply goes out |
| Autonomy gate | May the bot do this without asking the owner? | High. Money moves or something is published |
5. How the owner speaks to Petra #
The owner speaks to Petra in three places: the chat in the app, email and WhatsApp. This part shows what the owner sees in each place.
Cards in the chat with Petra #
This is an important use case. The owner speaks to Petra in the chat, and Petra shows cards in the chat. A card is a small part of a screen in a message. The owner reads the card or selects a button on it, and does not go to a different screen.
This picture shows how the chat looks. The names and the numbers are examples.
The chat with Petra uses OpenUI. This is a decision, and it is a part of the MVP. We make our own components with the tensquads design.
| Card | When Petra shows it | What the owner can do |
|---|---|---|
| Table | A result with rows, such as the list of competitors | Read it |
| Website preview | Angkor made or changed the page | See the page before it is public |
| Approval | An action is above a limit of the owner | Approve or reject |
| Payment | The credits are not sufficient for a task | Buy a credit pack, upgrade, or stop |
| Suggestions | The weekly review, or a signal | Accept or reject each suggestion |
The rules for the cards:
Each card also has a text form. Email and WhatsApp show the text form, because they cannot show a card.
Our code makes each approval. The model can only show an approval that the system made. A click goes to our code.
After the owner selects a button, the card shows the selection, and the buttons go away.
Petra can show only the cards in this table.
Email and WhatsApp for Petra #
When an owner signs up, the system gives Petra two addresses for that business. Only the owner writes to these addresses. The customers of the business do not use them.
An email address. The service is AgentMail. The system makes one inbox for each owner. The Petra of that owner is responsible for the inbox.
A phone number for WhatsApp. The service is AgentPhone. A number costs $3 for each month. Only a business in the United States or Canada gets a number. Each business has its own WhatsApp Business account.
A message that comes to one of these addresses is an event. It goes to Petra, the same as a message in the chat. The routing rules in the section above apply.
6. How a bot does a task #
Petra gives each task to one bot. This part shows how the bot starts, does the task and gives the result to Petra.
In simple words: bot, image, sandbox and state #
Read this section first. A bot does not run in a sandbox. A bot thinks in one place and works with its hands in a different place.
Cloudflare is where the thinking is done. Petra is there, and the loop of each bot is there. The loop is the code that asks the model "what is the next step?" and reads the answer.
boat.dev is where the work with the hands is done. A bot uses it only when it must operate a real computer: open a website in a browser, read the pages of a competitor, build a web page, or run code.
| Word | What it is | Where it is |
|---|---|---|
| Bot | A job description: the instructions, the skills and the list of permitted tools. It is not a machine | In our code |
| Image | A saved copy of a computer with the programs of that bot, such as a browser. It does nothing until the system starts it | Stored, ready to use |
| Sandbox | A running copy of the image, for one task. One image can make many sandboxes | boat.dev |
| State | All that must not be lost: the messages, the tasks, the approvals, the memory, and the record of each task | The Neon database |
The image is the template, and the sandbox is one computer made from the template. The system deletes the sandbox after the task. Nothing is lost, because the state was never in the sandbox.
When a sandbox starts
A sandbox starts only when the model asks for a tool that needs a real computer. A sandbox does not start for thinking, for writing an answer, or for reading the memory.
Example 1: no sandbox
A customer asks Kyoto: "Are you open on Sunday?"
The loop of Kyoto, on Cloudflare, reads the opening hours from the database.
The model writes the answer.
The answer goes to the check, and then to the customer.
boat.dev is not used. Thus the answer is quick.
Example 2: with a sandbox
The owner asks Petra: "Who are my competitors?"
Petra, on Cloudflare, gives the task to the loop of Machu, also on Cloudflare.
The model says: "I must read these five websites."
A browser is necessary to read a website. The system starts a sandbox on boat.dev from the image of Machu.
The sandbox reads the pages and gives the text to the loop. The same sandbox does all the reading for this task.
The model writes the result. The result goes to the check, and then to Petra.
The sandbox stops, and the system deletes it.
The system writes each step to the database. If the sandbox breaks at step 4, the system starts a new sandbox, and the task continues.
A sandbox cannot see the data of a different account or of a different task. A sandbox keeps no data after it stops, and it has no keys. If a sandbox breaks, the loop gets a failed tool result, and the system starts a new sandbox. The session, the memory and the trails are in the database, not in the sandbox.
Only Petra is always on. The loop of each other bot runs only while it has a task. A simple task, such as one answer by Kyoto, needs no sandbox, so it is quick. The repository has a boat.dev adapter now.
Inside a bot #
This section is a proposal. The design of the loop follows the agent loop of the Claude Agent SDK. The section shows what a bot contains and how its loop runs. The detail for the builders is in Part 9, "The loop in detail".
What a bot contains
| Part | What it is |
|---|---|
| Instructions | The role of the bot: what it does, what it does not do, and to whom it speaks |
| Skills | The method for each type of task. Example: how Machu does competitor research |
| Tools | The list of the tools that the bot can use. Example: the page reader for Machu |
| The loop | The code that runs the turns. It is the same for all the bots |
| The check | How the bot knows that the task is complete. Each type of task has its own check |
| The image | The programs that the tools need in a sandbox, such as a browser. The loop is not in the image |
The model is not in the image. The bot calls the large model through a port. Each model is a plug-in behind this port, so we can replace the model and change no bot. For this reason, we write our own loop with the design of the reference, and we do not use the Agent SDK as the engine, because it runs only Claude models.
What the loop gets when a task starts
The task from Petra, with the necessary result.
The core of the memory of that business.
The rules and the limits of the owner.
The id of the account and the id of the task.
The loop
Receive. The loop gets the task from Petra, the instructions of the bot, the definitions of its tools, the core of the memory and the rules.
Evaluate. The model reads all of this and answers. The answer has text, one or more tool requests, or both.
Execute. Our code does a check of each tool request against the rules, and then it runs the tool. A tool that needs a browser or code runs in the sandbox. Tools that only read can run at the same time. Tools that change something run one after the other. The results go back to the model.
Repeat. Steps 2 and 3 are one turn. The turns continue until the model answers with no tool request.
Result. The last answer is the result. A checker that is not the maker tests the result. Then the bot gives the result and the evidence to Petra.
A simple task, such as one answer by Kyoto, needs two or three turns. A research task by Machu can need many turns.
How the loop stops
The loop stops in one of these ways. Each way has a name, and Petra reads the name to know what to do.
| How the loop stops | Meaning | What Petra does |
|---|---|---|
| Success | The model made no more tool requests. This is a claim, not a proof | Sends the result to the check. If the check passes, Petra gives the report to the owner |
| Maximum turns | The loop reached its limit of turns | Tells the owner. The system gives the credits back |
| Maximum budget | The task reached its limit of cost | Tells the owner. The system gives the credits back |
| Error | An error stopped the loop | Starts the task again one time. Then tells the owner |
Each result has the cost, the number of turns and the id of the session, also when the task fails. The super admin dashboard uses these numbers.
What a bot cannot do
It cannot send a message to the owner. Only Petra does this.
It cannot give its task to a different bot.
It cannot do an action above a limit of the owner. It asks Petra, and Petra asks the owner.
It cannot see the data of a different account or of a different task.
How a result is checked #
A loop that runs alone also makes mistakes alone. Thus "done" must be a result that is tested, not a statement by the bot. The rule: the model that did the task never decides that the task is complete. In this section, the maker is the bot that did the task, and the checker is the part that tests the result.
The five layers
A written check for each type of task. The definition of the bot has a list of conditions that can be tested. Example for Machu: five competitors, each with a source that opens.
Evidence with each result. The maker gives evidence for each condition: a link, a screenshot or a measured number.
Tests by code. Our code tests what it can with no model: the links open, the page loads, the price is in the limits, and the text does not break a rule in the core of the memory.
The checker. A different model tests each condition that code cannot test.
The owner and the team. An action with money, or an action that the public sees, needs the approval of the owner. Each week, the team examines a sample of the tasks. A result that the owner rejects or changes becomes a test case.
The checker
| Point | Design |
|---|---|
| Where it runs | In the stop hook of the loop plug-in. The checker is a separate plug-in, so we can replace it |
| What it gets | Only the task, the conditions, the result and the evidence. It does not get the turns of the maker, so the maker cannot persuade it |
| Which model | A different model plug-in from the maker, or Jev, with different instructions |
| What it answers | For each condition: yes or no, and how sure it is |
| What it can do | It can only read. It can open a link to test the evidence. It cannot change anything |
| If an answer is no | The result goes back to the maker with the reason, for one more try. After a second no, the task fails. Petra tells the owner, the system gives the credits back, and the task goes to the triage list of the super admin |
| The cost | It is a part of the price of the task |
How we know that the checker is good
Each answer of the checker goes in the trail.
We compare the answers of the checker with what the owner did later. If the owner rejects a result that the checker accepted, the checker made a mistake.
The checker has its own test cases: wrong results that it must find.
The numbers in this section are a start: one more try, and a sample each week.
7. Credits and prices #
Each account can use all the bots. Before a task starts, the system does a check of the credit balance of the account. If the balance is not sufficient, the task does not start. The system then tells the owner to pay or to upgrade. There are three subscription packages, as in the design: Starter $49, Growth $149 and Scale $399 for each month. Each package includes a number of credits. The owner can also buy credit packs. The credits come in increments of 1,000. Starter includes 1,000 credits, Growth 3,000 and Scale 8,000. A credit pack is 1,000 credits for $50.
The picture shows the check of the credits for one task.
The pricing structure #
This structure is a proposal. Moe decided five points: one credit is 5 cents, the credits in each package, the credit pack, the system takes the credits before a task starts, and a failed task costs nothing. The other numbers are a start. We change them by trial and error, with the data from the super admin dashboard.
1. The value of a credit
1,000 credits cost $50. One credit is 5 cents.
2. The subscription packages
| Package | Price for each month | Credits for each month |
|---|---|---|
| Starter | $49 | 1,000 |
| Growth | $149 | 4,000 |
| Scale | $399 | 10,000 |
3. The credit packs
| Pack | Price |
|---|---|
| 1,000 credits | $50 |
An owner buys a pack when the credits of the month are not sufficient. Start with one pack size. Add larger packs only if owners ask for them.
4. The price of each type of task
These prices are a first estimate. We do not know the real costs at this time.
| Bot | Type of task | Price in credits | Price in money |
|---|---|---|---|
| Petra | A chat message | 0 | $0 |
| Machu | Competitor research | 200 | $10 |
| Angkor | Build a website or a menu page | 400 | $20 |
| Angkor | Change one thing on the page | 40 | $2 |
| Kyoto | Answer one customer message | 4 | $0.20 |
| Greenwich | Examine the Google Maps listing | 100 | $5 |
| Greenwich | Write a draft reply to one review | 10 | $0.50 |
| Greenwich | Weekly report | 40 | $2 |
| Petra | Weekly performance review | 0 | $0. A part of each package |
| Angkor | Audit of the website | 0 | $0. A part of each package |
With these prices, a Starter owner can do one research task, one website, five changes and 50 customer answers in one month.
5. The rules
The system takes the credits before the task starts.
If the task fails, the system gives the credits back.
The system uses the credits of the subscription first, and then the credits of a pack.
The credits of the subscription stop at the end of the month. The credits of a pack stay for 12 months.
A chat with Petra costs no credits, so the owner can always ask a question. The weekly performance review by Petra and the audit of the website by Angkor are a part of each package and also cost no credits. Petra tells the owner the price of a task only when the credits are not sufficient for it.
The 14-day trial gives 600 credits. This is sufficient for one research task and one website.
6. How we adjust the prices
Each week, the team reads the super admin dashboard.
The target: the real cost of a task is 30% of its price or less.
If the real cost is above 40% of the price, increase the price.
If the real cost is below 15% of the price, the team can decrease the price.
A new price applies to new tasks only.
Price, cost and the super admin dashboard #
The owner pays a fixed price for each type of task. The price does not change if the task uses more work than usual. Two words are important here:
Price is the number of credits that the owner pays.
Cost is the money that the task costs us: model use, sandbox time and external services.
The team uses the dashboard to compare the price with the real cost. If the cost is too near the price, the team changes the price list.
The system reads the price from the price list.
The system does a check of the credit balance.
The cost estimator calculates the cost that we expect for the task.
Petra gives the task to the loop of the bot.
The loop runs until the task is complete. It uses a sandbox only for a tool that needs a real computer.
The result goes to the check, and then to Petra. If a sandbox started, it stops.
The system records the price and the real cost.
The super admin dashboard shows the price and the real cost for each type of task.
The team changes a price when it is necessary. The new price applies to new tasks only.
What the dashboard shows
| Column | Meaning |
|---|---|
| Type of task | For example "competitor research" or "build a website" |
| Price | The credits that the owner pays |
| Average real cost | The average cost of the tasks of this type |
| Difference | The price minus the real cost |
| Number of tasks | How many tasks of this type the bots did |
| Tasks above the price | How many tasks had a real cost above their price |
The repository has a super admin area now, with a Companies screen and a Squad images screen. This dashboard is a new screen. It needs a design before we build it.
8. What the squad remembers and learns #
The squad keeps what it learns about the business. This part shows the memory, the trails and how the system uses them to improve.
Memory #
The squad remembers the business, so the owner does not have to give the same information again. The memory has four layers:
The full record of all messages.
The notes that each bot writes after a task.
One page for each subject, such as the menu, the suppliers and the competitors.
A small core that each task reads.
The picture shows the four layers. The core is small, and the record is large.
Each night, a job corrects and combines the notes. A sandbox keeps no memory.
For the builders. The four layers in the database:
| Layer | Contains | Who writes it | When a task reads it |
|---|---|---|---|
| Record of messages | Each message and each event. Nothing is changed or deleted | The system | Only by search |
| Notes | What a bot learned in a task | The bot that did the task | Only by search |
| Pages | One page for each subject: menu, suppliers, competitors, customers | One bot for each page | By search, or by a link from the core |
| Core | A small list with a size limit, and the preferences of the owner | The night job and the owner only | Each task reads it, with the limits and the rules |
Each row has its origin (owner, bot, not trusted, system), its source and its date. The system sets them. Only the rows from the owner and from a bot can go into the core.
A preference of the owner is an instruction. A new preference replaces the old one. The facts are separate.
The search uses words and meaning together. It gives more weight to new and important rows. It stays in one account.
Before the system makes a long chat shorter, the bot saves the important points as notes.
Each night, a job for each account compares the notes with the record of messages and combines them. It keeps the earlier version and a list of the changes.
A sandbox keeps only a temporary copy for reading.
The Memory screen (design proposal). The owner uses this screen to read and correct the memory of the squad. It is a new item in the menu, below Rules.
The screen has three areas:
Petra always remembers. This is the small core that each bot reads before each task. The owner can add, edit or forget an item. The maximum is 20 items.
Pages. One page for each subject, such as Menu, Competitors and Customers. Each fact shows who found it and its sources. The owner can correct a fact or tell the squad to forget it.
Recent changes. A record of each change to the memory. The owner can undo a change for 30 days.
The rules of the screen:
The word of the owner always wins. After the owner corrects a fact, the fact belongs to the owner, and no bot can change it.
When Petra is not sure about an old fact, she asks the owner: "Still correct?"
When the owner forgets a fact, it goes out of all the bots at the same time.
This is a proposal. The numbers 20 and 30 are a start. The text and the colours use the tensquads design tokens.
Trails #
A trail is the full record of one task. It contains each message, each use of a tool, each decision and each approval, in sequence. The team uses the trail to see what a bot did and why. The system keeps a trail for one month. Only the super admin of tensquads can see a trail. The owner cannot see it. The system keeps the approval records for more than one month, as evidence of each approval.
For the builders. What the trail contains, and what the plan has now:
| Part of the trail | Status | Source |
|---|---|---|
| Messages between bots | In the plan | The system puts each event in sequence and writes it to the database |
| Task results and evidence | In the plan | Each task has a check. The bot sends a result with evidence |
| Approvals | In the plan | Each approval records the rule, the limit and the person who approved |
| Calls to the model | Missing | Record each input and each reply as an event. This shows why a bot did an action |
| Uses of a tool | Missing | The loop records each use of a tool and its result while it works, not only the last result |
| Decisions | Missing | One row for each question to the decision model: the question, the answers, how sure, the level and the time |
How we store the trail
One table. The system only adds rows. It does not change a row.
One id for each task. It connects all the rows, from the message of the owner to the last result. One query gives the full trail.
Large items go to object storage (Cloudflare R2): screenshots, copies of pages and long records. The row keeps a link and a hash.
The screens read views that the system calculates from the table.
A sandbox keeps nothing. When a sandbox stops, no trail is lost.
Learning #
The system uses the trails to improve in two ways. For one business, the squad learns the preferences of that owner, and Petra recommends changes to the rules. For the full product, a task that failed becomes a test case. First, the system removes the customer data. Then the tensquads team examines the test case. A change to a bot must pass these tests before release.
The signals that the trails give
| Signal | What it tells us |
|---|---|
| The check passed or failed, on the first try or after more tries | If the bot can do the task |
| The owner approved, rejected or changed an approval | If the decision of the bot agrees with the decision of the owner |
| The owner asked for a change | The result was not what the owner wanted |
| The task stopped, took too long or was lost | Where the loop breaks |
| How sure the decision model was, compared with what the person did later | If the levels are correct |
| The time and the cost of each task | If a change made the task slower or more expensive |
Loop 1: for one business
After each task, a bot writes a note of what it learned.
Each night, a job compares the notes with the trail, combines them and updates the core of the memory.
A correction from the owner becomes a preference. A preference is stronger than a note of a bot.
Petra recommends changes to the rules from what she sees. Example: "You approved 12 refunds below $20. Do you want to increase the limit?" The owner decides. The system does not increase its own limits.
Loop 2: for the full product
Each task that failed, or that the owner asked to change, can become a test case. First, the system removes the customer data.
The image of each bot has a set of these test cases. A change to a skill or to a prompt must pass the set before release.
A change goes out in three steps: Draft, Beta, Stable. We compare the signals between the steps before we continue.
If a change makes a signal worse, we go back to the old version. The old plug-in is still there.
The failures that occur again and again go to the counts of bugs and requested features on the Squad images screen.
The safety rules
The data of one account does not go to a different account. Only test cases with no customer data, and totals, go across.
The owner can always read and correct what the squad learned.
A test or a person approves each change. No bot changes its own skills.
9. How we build it #
This part is for the persons who build the system. It gives the rules for the code, the tools, and the rule for each feature.
Architecture #
Four rules tell us how to build the code. The repository obeys the first two rules in part. The notes tell you what is there now and what to add.
Domain-driven design. We divide the code into business areas, not into technical layers. Each area has its own words, data and rules. Each area is one plug-in. The areas use events to send information to each other. No area reads the tables of a different area. The screens, the code and the documents use the same word for the same thing.
| Area | What it owns | In the code today |
|---|---|---|
| Platform | Accounts, plans, subscriptions | Yes |
| Squads | Bots, skills, sandboxes | Yes |
| Bus | Events between bots, shared state | Yes |
| Policy | Rules, limits, approvals | Yes |
| Catalog | Bot images, bugs, feature requests | Yes |
| Conversation | Chat threads and messages | Yes |
| Master | Petra's loop: tasks, checks, routing | Yes |
| Billing | Credits, packages, top-ups | To add |
| Memory | Notes, pages, the core | To add |
Anti-corruption layer. Our code does not use the words of an external service. We define a port for each external service in our own words. An adapter behind the port changes our words into the words of the service. The names and the data shapes of the service stop at the adapter.
The picture shows four of the ports. The table below shows all of them.
| Outside service | Our port | Status |
|---|---|---|
| boat.dev sandboxes | MachineProvider | Exists |
| Cloudflare queues | EventBus | Exists |
| Neon database | Repositories | Exists |
| Jev or Sage | Decider | Port exists, no adapter yet |
| Large model provider | A model port | To add |
| Google Maps (Greenwich) | A listings port | To add |
| Payments (credits) | A payments port | To add |
| AgentMail (email for Petra) | A mailbox port | To add |
| AgentPhone (WhatsApp for Petra) | A messaging port | To add |
The benefit: we can replace Jev with Sage, or replace one payment provider with a different one, and no business rule changes. A test makes sure of this. No file in a business area can import an adapter or an external library.
Keys. The keys of all the outside services are in a vault: the model, Google Maps, AgentMail, AgentPhone and payments. Our code calls each service through a proxy, and the proxy adds the key. The model and the sandbox do not see a key. Thus an attack on a bot cannot get a key.
Adversarial review. The decisions set the architecture. A pull request does not change it. For all other requirements, a reviewer tries to find a fault. The reviewer is not the builder. The reviewer must show evidence for each requirement. A report of "no fault found" without evidence is a fault.
| Requirement | The reviewer tries to |
|---|---|
| Security | Read another account's data. Hide an instruction in a review or a web page that a bot reads |
| Money safety | Make a bot refund or pay above the limit, or run a task without credits |
| Reliability | Stop a sandbox in mid-task. Send the same message twice |
| Privacy | Find customer data in a test case, a log or another account's memory |
| Performance | Find a page or a reply that is too slow |
| Accessibility | Use every screen with the keyboard only |
| Cost | Make one task spend credits without limit |
The Reviewer role is in the repository now, for screens. This rule adds the requirements in the table above to that role.
Plug-in framework. Each part of the system is a plug-in, as in the DeepSeek projects. Thus we can replace a part without a restart. The base is there now. We must add four tests that prevent drift:
You can remove a plug-in, and it leaves nothing behind.
A plug-in does not import a different plug-in.
Each piece of state has one writer.
The documents agree with the code.
Where each part runs #
This section shows where each part of the system runs, and which parts are always on. The app and Petra are always on. A bot is not a server. The loop of a bot runs on Cloudflare while the bot has a task. A sandbox runs only the tools that need one.
| Part | Where it runs | Always on | Notes |
|---|---|---|---|
| The app and the chat | Cloudflare Workers | Yes | The owner uses the app in a browser |
| Petra | Cloudflare, one Durable Object for each account | Yes | She receives each message and each event. She is the only writer of the state |
| Messages between the bots | Cloudflare Queues | Yes | Petra sends a task to a bot, and the bot sends the result |
| The tools of a bot that need a sandbox | A sandbox on boat.dev, started from the image of the bot | No. A sandbox starts when a tool needs it | The sandbox stops after the task and keeps no data |
| The state: accounts, rules, memory, trails | Neon database | Yes | One database for the MVP, with a second safety layer |
| Large items of a trail | Cloudflare R2 | Yes | Screenshots, copies of pages and long records |
| The websites that Angkor makes | Cloudflare Pages | Yes | Angkor publishes a website only after the owner approves it |
| Email for Petra | AgentMail | Outside service | A message arrives as an event and goes to Petra |
| WhatsApp for Petra | AgentPhone | Outside service | A message arrives as an event and goes to Petra |
| Sign-in | Clerk | Outside service | For the owners and the super admin |
| The large model | OpenAI | Outside service | It makes the plan of a task and writes text |
| The fast decision model | Jev | Outside service | It answers small questions |
| Payments | Not selected | Outside service | Subscriptions and credit packs |
| Google Maps | Not selected | Outside service | The listing and the reviews, for Greenwich |
| The loop of each bot | Cloudflare Workers | Only while the bot has a task | The loop keeps no state. It reads the session from the database, asks the model and runs the tools |
| The keys of the outside services | A vault, behind a proxy | Yes | The proxy adds the key to each call. The model and the sandbox do not see a key |
Each outside service is behind a port, as the Architecture section shows. Petra does not run all the time. She starts when a message or an event comes, does her work, writes the state to the database, and then waits. The loop runs on Cloudflare and calls the large model through the model port. A sandbox does not call the model. The keys of all the outside services are in a vault, and each call goes through a proxy that adds the key.
Where the state is #
Keep the state out of Petra. Petra reads and writes the state, but the database keeps it. If Petra stops or gets an update, no data is lost. Petra starts again and reads the state from the database.
| State | Where it is | Who writes it |
|---|---|---|
| Messages, tasks, approvals, trails | The database | Petra only |
| Memory of the business | The database | Petra only. A bot sends a note to Petra |
| Rules, limits, credit balance | The database | Petra only |
| The sequence of events for one account | Petra keeps a work copy | Petra only |
| Keys and passwords | A key store | The super admin |
| Data in a sandbox | Nothing stays after the sandbox stops | The bot, during one task |
One writer for each account prevents two bots from changing the same data at the same time. The plan agrees with this recommendation: Petra runs on Cloudflare, and the database is Neon.
One database for all the businesses, or one store for each business. One database can hold 10,000 businesses; the quantity is not the problem. The risk is isolation: with one database, one error in the code can show the data of one business to a different business.
| Option | How it operates | Good | Bad |
|---|---|---|---|
| A. One database for all | Each row has the identity of its business. The plan uses this now | Simple. One update for all. The super admin reads all the data easily | One error in a filter can show data to the wrong business |
| B. One database for each business | Neon makes a database for each business | Strong isolation. Easy to delete or restore one business | Each change to the tables runs 10,000 times. Reports for all the businesses are more difficult |
| C. Petra on her own machine, with the state on the machine | One machine for each business that is always on | Strong isolation | 10,000 machines that are always on. If a machine fails, its data can be lost. Reports must ask 10,000 machines |
| D. A private store in each Petra, and one central database | Each Petra keeps the data of her business in her own private store on Cloudflare. A central database keeps only the data that is for all: accounts, subscriptions, credits, prices, costs | Strong isolation with no machine that is always on. Cloudflare keeps the copies | A change to the plan. The code that reads Neon now must change |
The decision: option A for the MVP, with a second safety layer in the database. The second layer makes the database refuse a row that is not for the business that asks. Then option D, when the number of businesses increases or when a customer asks for isolation. We do not use option C.
The loop in detail #
This section is for the builders. Part 6 shows the loop in simple words. This section gives the controls, the hooks, the context, the session, the plug-ins, and how we add a new bot.
The controls of the loop
| Control | What it does | How tensquads uses it |
|---|---|---|
| Permitted tools | The list of the tools that a bot can use | Each bot has its own list. A tool that is not on the list is refused |
| Permission mode | What occurs when a tool needs an approval | No person watches the loop. Thus a request that is not permitted is refused, and the bot asks Petra |
| Maximum turns | The limit of turns | One limit for each type of task |
| Maximum budget | The limit of cost | One limit for each type of task, far above the normal use |
| Effort | How much the model thinks in each turn | Low for a simple answer by Kyoto. High for research by Machu |
When our code refuses a tool request, the model gets the refusal as the result. Then the model tries a different method, or it reports that it cannot continue.
The hooks
A hook is our code that runs at a fixed point of the loop. A hook does not use the context of the model.
| Hook | When it runs | How tensquads uses it |
|---|---|---|
| Before a tool | Before the tool runs | Applies the rules and the limits of the owner. It can refuse the request |
| After a tool | After the tool gives its result | Records the step in the trail |
| Stop | When the loop completes | Does the check of the result. Saves the state of the session |
| Before the context is made shorter | When the context is almost full | Nothing is lost. The full record is already in the session |
The context
The context is all that the model can read in one turn: the instructions, the tool definitions, and the earlier turns with their tool results. It becomes larger with each turn. When it is almost full, the loop makes a summary of the old turns. A summary loses information, and we cannot get that information back from the summary. Thus the full record of the task stays in the session, outside the context. The loop can read an old part of the session again when the model needs it. The permanent rules are in the instructions of the bot, not in the task message.
Stop and continue
Each task is a session with an id. The session is the full record of the task: each message, each tool request and each result, in sequence. The system only adds to it. It is in the database, not in the sandbox and not in the loop. It is the same record as the trail. Because the loop keeps no state, a new loop can read the session and continue from the last event. When a bot needs an approval, the loop and the sandbox stop. After the owner approves, a new loop continues the session. This is a decision.
The loop as a plug-in
The loop is one plug-in, and each bot is one plug-in. No bot contains loop code.
| Plug-in | What it gives |
|---|---|
| The loop plug-in | One port, "run a task". It takes the definition of a bot and a task, and it returns a result. The engine of the loop is behind this port, so we can replace the engine and change no bot |
| A bot plug-in | The definition of one bot: instructions, skills, permitted tools, the check, and the limits and the effort for each type of task. Also the price of each type of task |
| Policy | The hook before a tool: the rules and the limits of the owner |
| Trails | The hook after a tool: the record of each step |
| Memory | The core of the memory at the start, and the hook before the context is made shorter |
| Billing | The credits before the task, and the cost of the result |
| A model plug-in | One model behind the model port. The loop sends the context to the port and gets the answer with its tool requests. To use a different model, we add a new model plug-in and change the setting. The loop and the bots do not change |
The loop plug-in has the hook points. The other plug-ins add their hooks to these points. When we remove a plug-in, its hooks go away with it, and it leaves nothing behind.
When the model changes
A rule in the loop that helps a weak model can make a strong model slower. When we change the model plug-in, we examine the loop again. We run the test cases of each bot, and we remove each rule that does not help.
How we add a new bot
A new bot is one new plug-in. No other plug-in changes.
Make one folder for the bot, with its definition: instructions, skills, permitted tools, the check, the limits, and the price of each type of task.
If the bot needs a new outside service, add a port and an adapter for it.
Add the test cases of the bot.
Add the plug-in to the list of plug-ins. Then Petra finds the bot in the list of what each bot can do, the price list has its prices, and the system builds its image.
The roadmap bots and the future squads come in this way.
Technologies and tools #
This table shows each tool, its use, and its status. "In the repository" means that the code uses the tool now.
| Area | Tool | Use | Status |
|---|---|---|---|
| Language | TypeScript | All the code | In the repository |
| Web app | TanStack Start, React, Vite | The screens and the server functions | In the repository |
| Hosting | Cloudflare Workers, Durable Objects, Queues | Runs the app, Petra and the messages between bots | In the repository |
| Database | Neon Postgres, Drizzle | Stores the accounts, the rules, the memory and the trails | In the repository |
| Sign-in | Clerk | Sign-in for the owners and the super admin | In the repository |
| Plug-in core | cordis | Loads each business area as a plug-in | In the repository |
| Bot sandboxes | boat.dev | Runs the tools of each bot in an isolated sandbox | In the repository |
| Service setup | Stripe Projects (projects.dev) | Sets up Cloudflare, Neon and Clerk. Adds new services, provisions them, and manages their cost | In the repository |
| Tests | Playwright, axe | Tests each screen, records video, examines accessibility | In the repository |
| Behaviour models | TLA+ | Proves that a state model has no broken rule | In the repository |
| Format and lint | Biome | Keeps the code in one style | In the repository |
| Automatic checks | GitHub Actions | Runs the tests on each pull request | In the repository |
| Large model | OpenAI | Plans tasks and writes text. The model is a plug-in behind a port, and we can replace it | In the plan |
| Fast decision model | Jev, from TypeSafe | Fast answers to small questions | In the plan |
| Page reader | Scrapling, on boat.dev | Reads the pages of competitors for Machu | In the plan |
| Website publishing | Cloudflare Pages | Publishes the pages that Angkor makes | In the plan |
| Payments | Not selected | Subscriptions and credit packs | Open |
| Google Maps | Not selected | The listing and the reviews for Greenwich | Open |
| Email for Petra | AgentMail | Gives each Petra her own email inbox at sign-up | Suggested by Moe |
| WhatsApp for Petra | AgentPhone | Gives each Petra a phone number that receives WhatsApp messages | Suggested by Moe |
| Chat with Petra | OpenUI (github.com/thesysdev/openui) | Shows tables, previews and approvals in the chat while the model writes its answer | Decided. A part of the MVP, with our own components. Suggested by Moe |
Clear expectation and a video for every feature #
We do not start a feature until its expectation is written. We do not accept a feature until a person sees it operate.
Write the expectation before the work starts. Use simple words. Write what the feature does, who uses it, and what the correct result is. Use the cases in Part 12 as the model: one line for the action of the owner, and one line for the necessary result.
The coding agent builds the feature. It builds only what the expectation says.
The coding agent records a video. The video shows the feature from start to end. It shows the written cases in sequence.
The coding agent attaches the video to the pull request. The person who examines the pull request sees the video and compares it with the expectation.
A difference is a fault. If the video does not show a written case, the pull request goes back. If the video shows something that the expectation does not include, the pull request also goes back.
The repository asks for screenshots and automated tests now. This rule adds a video. The test tool that runs the automated tests can also record the video. Thus the agent records the tests while they run.
10. Feature list #
This is the only list of the features that we build. Add one row for each feature that you want. Write your name in the "Added by" column. Set the priority. Parts 3, 4 and 5 give an explanation of each feature.
| # | Feature | Group | Priority | Status | Added by | Notes |
|---|---|---|---|---|---|---|
| 1 | Petra, the master and chief of staff | MVP bot | High | Proposed | Moe | Talks to the owner. Directs the other bots |
| 2 | Machu, the research bot | MVP bot | High | Proposed | Moe | Researches the competition |
| 3 | Angkor, the website and menu builder | MVP bot | High | Proposed | Moe | Builds the website and the menu |
| 4 | Kyoto, the support bot | MVP bot | Medium | Proposed | Moe | Handles support when the business needs it |
| 5 | Greenwich, the Google Maps bot | MVP bot | Medium | Proposed | Moe | Handles the business on Google Maps |
| 6 | Credits and subscriptions | Billing | Medium | Proposed | Moe | Starter $49, Growth $149 and Scale $399 for each month, each with credits. Credit packs for more credits. A task starts only when the balance is sufficient |
| 7 | Domain-driven design | Architecture | High | Proposed | Moe | The code is split by business area, in the business's own words |
| 8 | Anti-corruption layer | Architecture | High | Proposed | Moe | Outside services never leak their terms into our code |
| 9 | Adversarial review of all non-architectural requirements | Architecture | High | Proposed | Moe | A reviewer tries to break each requirement and shows evidence |
| 10 | Plug-in framework with tests that stop drift | Architecture | Medium | Proposed | Moe | Everything is a plug-in, as DeepSeek does |
| 11 | Routing | System | High | Proposed | Moe | How a task reaches the right bot |
| 12 | Memory | System | Medium | Proposed | Moe | What the squad remembers about the business |
| 13 | Trails | System | High | Proposed | Moe | A record of what every bot did and why, kept one month |
| 14 | Learning | System | Low | Proposed | Moe | The system improves from its trails |
| 15 | Fast decision model (Jev) | System | Low | Proposed | Moe | A small model for quick yes/no judgements. We test it during the MVP |
| 16 | Clear expectation and a video for every feature | Process | High | Proposed | Moe | The expectation is written before work starts. The coding agent records a video of the feature working, for the person who checks the pull request |
| 17 | Fixed price for each type of task | Billing | Medium | Proposed | Moe | A price list gives the credits for each type of task |
| 18 | Credit ledger | Billing | Medium | Proposed | Moe | A record of each credit that an account gets or uses |
| 19 | Real cost record for each task | Billing | High | Proposed | Moe | The system records what each task costs us: model use, sandbox time, external services |
| 20 | Bot image, sandbox and loop | System | High | Proposed | Moe | The loop of a bot runs on Cloudflare. It starts an isolated sandbox on boat.dev from the image of the bot only for a tool that needs a real computer. The loop gives the result to Petra |
| 21 | Cost estimator | Billing | Low | Proposed | Moe | Before a task starts, the estimator calculates the cost that we expect |
| 22 | Super admin dashboard: price and real cost | Super admin | Medium | Proposed | Moe | For each task, the team sees the price that we charge and the real cost |
| 23 | Price change by the super admin | Super admin | Low | Proposed | Moe | The team changes the price of a type of task. The new price applies to new tasks |
| 24 | Trail viewer for the super admin | Super admin | Medium | Proposed | Moe | The tensquads team sees the trail of each task. The owner does not see it |
| 25 | Stripe Projects (projects.dev) | Architecture | Medium | Proposed | Moe | We use it to add new services, to provision them, and to manage their cost. The repository uses it now for Cloudflare, Neon and Clerk |
| 26 | Second safety layer in the database | Architecture | High | Proposed | Moe | The database refuses a row that is not for the business that asks. For the MVP |
| 27 | Private store in each Petra, and one central database | Architecture | Low | Proposed | Moe | After the MVP. Each Petra keeps the data of her business. The central database keeps the data for all the businesses |
| 28 | PI-Starter: rules and checks for coding agents | Process | Low | Proposed | Moe | Later. Before we add it, select the web framework: Next.js or TanStack Start |
| 29 | Email address for Petra | Channels | Medium | Proposed | Moe | At sign-up, the system gives Petra her own email address. The service is AgentMail |
| 30 | WhatsApp number for Petra | Channels | Medium | Proposed | Moe | At sign-up, the system gives Petra a phone number that receives WhatsApp messages. The service is AgentPhone |
| 31 | Performance review and suggestions by Petra | System | Medium | Proposed | Moe | Petra reads the performance of the business each week and suggests changes to the website or to other areas. Jev gives a score to each suggestion. The review is a part of each package and costs no credits |
| 32 | Roles of the bots and the persons | System | High | Planned | Moe | Each bot has one role: what it does, what it does not do, and to whom it speaks. The persons are the owner, the customer of the business and the super admin |
| 33 | OpenUI for the chat with Petra | Architecture | Medium | Proposed | Moe | To consider. With OpenUI, Petra can show a table, a preview or an approval in the chat, not only text |
| 34 | Cards in the chat with Petra | System | High | Proposed | Moe | Petra shows cards in the chat: a table, a website preview, an approval, a payment message and suggestions. A very important use case. The chat uses OpenUI |
| 35 | Check of a result by a separate checker | System | High | Proposed | Moe | The model that did the task does not decide that the task is complete. Our code tests what it can. A checker with a different model tests each other condition. Refer to Part 6 |
Roadmap and future squads #
These bots and squads are not in the MVP, and they are not in the feature list above. The roadmap bots come first. The future squads come after them. Moe will add more to the roadmap.
| Name | Role | When | Added by |
|---|---|---|---|
| Analytics bot | Roadmap | Moe | |
| Accounting bot | Roadmap | Moe | |
| Finance bot | Roadmap | Moe | |
| Paid ads management | Runs paid ads | Future | Moe |
| SEO growth specialist | Grows organic traffic | Future | Moe |
| Order management | Manages orders | Future | Moe |
| Catalog management | Manages the product catalog | Future | Moe |
| Integration / channels manager | Integrates with other marketplaces | Future | Moe |
11. Decisions #
Each row is one decision that Moe made. The parts above use these decisions. To change a decision, add a question to Part 14.
| Area | Subject | Decision |
|---|---|---|
| Credits and prices | Price of a task | Each type of task has a fixed price. A cost estimator calculates the expected cost. The super admin dashboard compares the price with the real cost |
| Credits and prices | Packages | Starter $49, Growth $149 and Scale $399 for each month, as in the design. The design does not change |
| Credits and prices | Credits in each package | Starter 1,000 credits, Growth 3,000 and Scale 8,000 |
| Credits and prices | Credit pack | 1,000 credits for $50 |
| Credits and prices | Value of a credit | 5 cents. We adjust this value by trial and error |
| Credits and prices | Time of payment | The system takes the credits before the task starts |
| Credits and prices | Failed task | The owner does not pay. The system gives the credits back |
| Credits and prices | Price before the task | Petra tells the owner the price only when the credits are not sufficient |
| Credits and prices | Cost limit | Each type of task has a maximum of turns and a maximum budget. These are safety limits only, far above the normal use. When a limit stops a task, the owner gets the credits back. The dashboard shows the tasks that cost more than their price |
| Credits and prices | Weekly performance review | A part of each package. It costs no credits. Petra does it each week. The data of the MVP is sufficient for the first version |
| Credits and prices | Website audit | A part of each package. It costs no credits |
| Petra and the bots | Decision model | We use Jev. We do the Jev test during the MVP. We can test Sage later |
| Petra and the bots | Signal | Three complaints of the same type in one week. This is a start, and we can change it |
| Petra and the bots | Reviews on Google Maps | Greenwich answers them |
| Petra and the bots | Always on | Only Petra is always on. The loop of each other bot runs on Cloudflare while the bot has a task. A sandbox starts only when a tool needs it |
| Petra and the bots | Start time of a sandbox | A simple answer by Kyoto needs no sandbox. For a task that needs one, measure the start time first. If a sandbox starts in more than 10 seconds, Kyoto keeps one sandbox ready for each business that has support on |
| Petra and the bots | Greenwich character | The new repository has the Greenwich file in assets/mascots |
| Petra and the bots | Future squads | Moe added them. They are in their own section below the feature list |
| Email and WhatsApp | WhatsApp service | AgentPhone (agentphone.ai) |
| Email and WhatsApp | Who writes to Petra | Only the owners |
| Email and WhatsApp | Cost of a number | $3 for each number for each month. AgentPhone adds no price for a WhatsApp message. Meta sends its own bill for the WhatsApp conversations |
| Email and WhatsApp | Inboxes | One inbox for each owner. The Petra of that owner is responsible for it. Before the first owner, the team must confirm that the AgentMail plan permits this number of inboxes |
| Email and WhatsApp | Countries of the numbers | Only the businesses in the United States and Canada get a number. A business in a different country gets the email address and the chat |
| Email and WhatsApp | WhatsApp Business account | One account for each business. The team must read the AgentPhone documents to learn how a business connects its account, and what Meta charges |
| Memory and trails | Trails | Only the super admin of tensquads sees a trail. The system keeps a trail for one month |
| Memory and trails | Approval records | The system keeps them for more than one month. The time is not defined |
| Memory and trails | Memory screen | The owner can read and correct the memory. The design proposal is in Part 8 |
| Memory and trails | Test cases from failed tasks | A failed task of one business can become a test case for all, after the system removes the customer data. The tensquads team examines each test case |
| How we build it | State | The database keeps the state. Only Petra writes it |
| How we build it | Database | One database for the MVP, with a second safety layer. Later, a private store in each Petra and one central database |
| How we build it | Limits of the private store | We confirm the size limit and the price when we have 500 businesses, or when an owner asks for isolation |
| How we build it | projects.dev | It is Stripe Projects. We use it to add new services, to provision them, and to manage their cost |
| The chat | OpenUI for the chat | We use OpenUI for the chat with Petra. It is a part of the MVP. We make our own components with the tensquads design. Each card also has a text form for email and WhatsApp. Our code makes each approval |
| How we build it | The model and the loop | Each model is a plug-in behind a port, and we can replace it easily. We write our own loop with the design of the Claude Agent SDK. We do not use the SDK as the engine, because it runs only Claude models |
| Petra and the bots | Approval in the middle of a task | The system saves the session, and the loop and the sandbox stop. After the owner approves, a new loop continues the session |
| How we build it | Calls to the model | The loop runs on Cloudflare and calls the model. A sandbox does not call the model. The system records the cost and the trail of each call |
| How we build it | Where the loop runs | Outside the sandbox, in our code on Cloudflare. The loop keeps no state. A sandbox is only a tool: run this, and give me the result. A task that needs no sandbox starts immediately |
| Memory and trails | Session record | The full record of a task is in the session, outside the context of the model. The loop can read an old part again. It is the same record as the trail |
| How we build it | Keys | The keys of all the outside services are in a vault, behind a proxy. The model and the sandbox do not see a key |
| How we build it | When the model changes | We examine the loop again. We run the test cases of each bot, and we remove each rule that does not help |
| Petra and the bots | Check of a result | The model that did the task does not decide that the task is complete. Our code tests what it can, and a separate checker with a different model tests each other condition. After a second failure, the task fails and the owner gets the credits back |
12. Test cases #
These are the success cases for the MVP bots. Select Yes, Later or No in the last column. Each case uses a restaurant or a grocery shop, the two types of business in the plan. In these cases, the owner is the person who has the account, and a customer is a person who buys from the business.
Petra (master / chief of staff) #
Petra is the only bot that speaks to the owner. These cases test her alone.
| # | Case | What the owner does | Success looks like | Test it? |
|---|---|---|---|---|
| P1 | Picks the right bot | Asks "Who are my competitors nearby?" | Petra sends the task to Machu, not to another bot. The trail shows her choice and reason | |
| P2 | Asks when unclear | Says "Fix my online stuff" | Petra asks one clear question before she starts any task. No bot runs until the owner answers | |
| P3 | Answers alone | Asks "What did the squad do today?" | Petra answers from the trail with the correct tasks and results. No bot is started | |
| P4 | Honest status | Asks "Is my website ready?" while Angkor is still working | Petra says it is in progress and what remains. She does not say it is done | |
| P5 | Reports a failure | A bot's task fails its check twice | Petra tells the owner what failed, in plain words, and offers a next step. She does not hide it | |
| P6 | Stops for approval | A task needs an action above the limit of the owner | Petra puts one approval in the inbox and waits. The action does not run before a yes | |
| P7 | Only Petra speaks | Any task that uses another bot | Every message that the owner sees comes from Petra. No other bot writes to the owner |
Petra and Machu (research) #
The owner asks Petra. Petra gives Machu the task. Machu returns the findings with their sources. Petra tells the owner.
| # | Case | What the owner does | Success looks like | Test it? |
|---|---|---|---|---|
| M1 | Finds real competitors | A restaurant owner asks "Who are my competitors?" | At least 5 competitors. Each is a real business of the same type in the same area, with a working link | |
| M2 | Compares prices | Asks "How do my prices compare?" | A table of competitor prices for like items. Every price has the page it came from | |
| M3 | Finds the gaps | Asks "What are they missing that I could offer?" | At least 3 gaps. Each one names the competitors it is based on | |
| M4 | Admits what it could not find | The business is in a small town with little online | Machu returns what it found and says what it could not. It invents no competitor and no price | |
| M5 | Plain summary | Any research task | Petra's summary fits one screen, uses no jargon, and links to the full findings | |
| M6 | Research feeds the website | Research is done, then the owner asks for a website | Angkor's page uses at least one finding from Machu, such as a gap or a price point |
Petra and Angkor (website and menu builder) #
The owner asks Petra for a website. Angkor builds it. Petra shows a preview link in the chat. Petra publishes the website only after the owner approves it.
| # | Case | What the owner does | Success looks like | Test it? |
|---|---|---|---|---|
| A1 | Builds a restaurant page | A restaurant owner says "Build my website" and gives name, address, hours and menu | A live preview link in the chat. The page shows the correct name, address, hours and every menu item with its price | |
| A2 | Builds a grocer page | A grocer gives a list of items | One page that lists every item given. No item is missing, added or renamed | |
| A3 | Works on a phone | Opens the preview on a phone | The page reads well at phone width with no sideways scroll. It loads in under 3 seconds | |
| A4 | Changes on request | Says "Change the price of the falafel wrap to $9" | Only that price changes. The preview updates and nothing else on the page moves | |
| A5 | Asks for what is missing | Asks for a site but gives no menu | Petra asks for the menu. Angkor invents no dish and no price | |
| A6 | Publishes only after a yes | Reviews the preview | The site goes live at its public address only after the owner approves. Before that, only the preview exists | |
| A7 | Fits the culture | The restaurant has a clear cuisine, such as Lebanese | The design reflects it in colour, type or imagery, and the owner rates it acceptable without a redesign |
Petra and Kyoto (support) #
Kyoto answers the messages of the customers of the business. Petra tells the owner what occurred and brings the approvals.
| # | Case | What happens | Success looks like | Test it? |
|---|---|---|---|---|
| K1 | Answers a simple question | A customer asks "Are you open on Sunday?" | Kyoto replies with the correct hours from the business's own data, within one minute | |
| K2 | Says when it does not know | A customer asks about something not in the data, such as parking | Kyoto says it will check and passes the question to the owner through Petra. It invents no answer | |
| K3 | Refund under the limit | A customer asks for a $15 refund; the owner's limit is $20 | Kyoto follows the owner's rule without asking. The trail records the rule it matched | |
| K4 | Refund over the limit | A customer asks for a $60 refund; the limit is $20 | No refund is made. Petra shows the owner one approval with the amount and reason. The refund runs only after a yes | |
| K5 | Angry customer | A customer sends an angry complaint | Kyoto stays polite, makes no promise it cannot keep, and Petra flags it to the owner the same day | |
| K6 | Owner's daily summary | The owner asks Petra "Any support issues today?" | Petra gives the correct count of messages, what was resolved and what waits for the owner | |
| K7 | Support is off until needed | A new business has not turned support on | Kyoto answers nothing. Petra offers to turn it on when the first customer message arrives |
Petra and Greenwich (Google Maps) #
Greenwich looks after the business's Google Maps listing. Anything the public will see goes through Petra to the owner for a yes first.
| # | Case | What the owner does | Success looks like | Test it? |
|---|---|---|---|---|
| G1 | Audits the listing | Asks "How does my Google listing look?" | Greenwich reports what is missing or wrong: hours, phone, category, photos, website link. Each point matches the live listing | |
| G2 | Updates the hours | Says "We now close at 10 pm on Fridays" | Petra shows the change for approval. After a yes, the live listing shows the new hours and nothing else changed | |
| G3 | Drafts a reply to a good review | A 5-star review arrives | Greenwich drafts a short reply that mentions what the reviewer said. It is posted only after the owner approves | |
| G4 | Handles a bad review | A 1-star review arrives | Petra tells the owner the same day with a calm draft reply. Nothing is posted without a yes. The draft admits no fault the owner has not confirmed | |
| G5 | Links the new website | Angkor publishes the site | Greenwich proposes adding the site and menu link to the listing. After a yes, the listing links to the live site | |
| G6 | Creates a missing listing | The business has no Google listing | Greenwich prepares the listing details and tells the owner the steps only they can do, such as verification. It does not claim the listing is live before it is | |
| G7 | Weekly report | Asks "How did we do on Google this week?" | Petra gives views, calls, direction requests and new reviews. The numbers match Google's own |
Petra and the cards in the chat #
The owner speaks to Petra in the chat, and Petra shows cards in the chat. Moe said that this use case is very important.
| # | Case | What the owner does | Success looks like | Test it? |
|---|---|---|---|---|
| D1 | A table card | Asks "Who are my competitors?" | Petra shows one table card in the chat, with one row for each competitor. The answer is not a long text | |
| D2 | A website preview card | Asks "Build my website" and gives the menu | Petra shows a preview card with the name, the hours and each menu item. The card says "preview" until the website is public | |
| D3 | An approval card | A $60 refund request comes, and the limit is $20 | Petra shows one approval card with the amount, the reason and two buttons. The refund occurs only after the owner selects "Approve" | |
| D4 | The card after a selection | Selects a button on an approval card | The card shows the selection, and the buttons go away. The owner cannot approve the same action two times | |
| D5 | A payment card | Asks for a task, and the credits are not sufficient | Petra shows a payment card with the price of the task and the balance. The task does not start | |
| D6 | A suggestions card | The weekly review occurs | Petra shows one card with three suggestions or fewer. Each one has its evidence and its price in credits | |
| D7 | The same answer on WhatsApp | The owner asks the same question on WhatsApp | Petra sends the same information as text. The text has all the facts of the card |
The judgement of Petra #
These cases show how Petra decides. In each case, Petra must make a decision that a fixed rule cannot make, and she must give her reason. Part 4, "How Petra decides", gives the sequence of questions.
| # | Case | What the owner does | Success looks like | Test it? |
|---|---|---|---|---|
| J1 | A request with no clear bot | Says "My customers cannot find us" | Petra selects Greenwich, because the problem is about Google Maps. She tells the owner her reason in one sentence | |
| J2 | A request for two bots | Says "I want to start a lunch offer" | Petra does the research with Machu first, and then asks Angkor to add the offer to the website. She tells the owner the sequence before she starts | |
| J3 | A request that no bot can do | Says "Do my taxes" | Petra tells the owner that no bot in the squad can do this. She starts no task and takes no credits | |
| J4 | A request that disagrees with a preference | The owner said before "Never mention delivery". Now the owner says "Add a delivery banner to the website" | Petra tells the owner about the disagreement and asks which one is correct. She does not select by herself | |
| J5 | A request to give Petra more freedom | Says "From now on, answer all the bad reviews without me" | Petra tells the owner that this changes a rule. She asks the owner to confirm the new rule. She does not increase her own limits | |
| J6 | Petra is not sure | A refund request comes with a reason that is not clear | Petra does not guess. She asks the owner, and no refund occurs before the answer | |
| J7 | The owner asks for the reason | Asks "Why did you ask Machu?" | Petra gives the reason in simple words. The reason agrees with the reason in the trail | |
| J8 | An event, not a signal | One customer complains about a long wait | Petra records the complaint and makes no suggestion. She can tell the owner why, if the owner asks |
Petra and the signals #
Petra reads signals and confirms them. She does not react to each piece of information. Moe gave the examples for these cases.
| # | Case | What occurs | Success looks like | Test it? |
|---|---|---|---|---|
| N1 | One complaint, and the website is slow | A customer says that the website does not respond | Kyoto answers the customer. Petra starts an audit of the website. The audit finds that the website is slow. Petra shows the owner the measurement and a suggested change | |
| N2 | One complaint, and the website is not slow | A customer says that the website does not respond | Kyoto answers the customer. Petra starts an audit. The audit finds no problem. Petra makes no suggestion to the owner, and she records the complaint | |
| N3 | One bad review | One review on Google Maps says that the food came after more than 45 minutes | Greenwich answers the review. Petra records the complaint. Petra makes no suggestion to the owner | |
| N4 | Three complaints of the same type | In one week, a third customer says that the food came after more than 45 minutes | Petra tells the owner about the signal. She shows the three complaints as evidence and suggests a change | |
| N5 | Three complaints of different types | Three bad reviews come. Each one is about a different problem | Petra does not count them as one signal. She makes no suggestion | |
| N6 | The same complaint in different words | One customer writes "we waited almost an hour". A second writes "the food took 50 minutes" | Petra counts the two complaints as the same type | |
| N7 | The owner rejects the suggestion | The owner rejects a suggestion from Petra | Petra does not make the same suggestion again, unless new evidence comes |
The whole squad #
These cases test the promise: a company can launch with tensquads.
| # | Case | What the owner does | Success looks like | Test it? |
|---|---|---|---|---|
| S1 | Launch in one conversation | A new restaurant owner says "Help me launch" | In one chat: competitor research, a published site with the menu, and a Google listing that links to it. The owner gave at most 3 approvals | |
| S2 | One change, everywhere | Says "We are closed on Mondays now" | The site, the Google listing and Kyoto's answers all show the new hours. Petra confirms each one | |
| S3 | A bot is down | The sandbox of Angkor fails during a build | Petra tells the owner there is a delay. The task continues in a new sandbox and completes. No work is lost and nothing is done twice | |
| S4 | Nothing sent twice | The network drops while Kyoto sends a reply | The customer receives the reply exactly once | |
| S5 | The trail is complete | Any finished task | The team can open the task and see every message, tool call, decision and approval, in order | |
| S6 | Memory carries over | The owner says once "Never mention delivery; we do not deliver" | A week later the site, the review replies and Kyoto's answers still follow it | |
| S7 | Two businesses stay apart | Two owners use tensquads on the same day | Nothing from one business appears in the other's chat, site, memory or trail |
How to measure. Run each chosen case 5 times. A case passes when all 5 runs meet "Success looks like". Where a row gives no number, the tensquads team judges it against the written line.
13. Research and sources #
This part contains the research behind the design. It shows what each reference says and what we take from it. The design is in Parts 4 to 9. Moe added all the topics.
Framework: everything is a plugin #
tensquads already has the base: a cordis core, one plug-in per domain area, skill updates as plug-in swaps. What it lacks is the tests that stop drift. DeepSeek's projects get their discipline from tests, not from the plug-in idea alone.
What it means in DeepSeek Harness (DSH). There is no privileged core. The model adapter, tool registry, session log and agent loop are each a plug-in. Each service has one owner and one typed key. Every registration returns a disposer, so unloading a plug-in removes all it added. Composition is data, and one command prints the booted tree.
How they stop drift. A dispose test for every registry. A boot test for each plug-in. Recorded-session snapshots. Config that is validated and fails loudly at load. Tests that check the docs match the code. The rule "what the model sees is logged".
Philosophy (dsh-superagent). Take little human attention and give much value. Act only on request or by a written rule. Ask one question at a time. Stop by impact. Report honestly. Few concepts, few settings. Start narrow.
Borrow, in order
| # | What | From | What changes in tensquads |
|---|---|---|---|
| 1 | Every registration is an effect with a disposer, plus a dispose test per plug-in | DSH | Proves "a removed plug-in leaves no trace" and the skill swap in decision 18 |
| 2 | Typed service keys with one owner each | DSH | Replaces the casts and per-plug-in branches in kernel.ts |
| 3 | Import-boundary tests | dsh-superagent | Domain imports no adapter; plug-ins do not import each other |
| 4 | One writer per state, as a test | dsh-superagent | Enforces decision 16 |
| 5 | A surface per caller (web, Durable Object, queue) | dsh-superagent | Splits the one wide Kernel class |
| 6 | Docs-match-code test | dsh-superagent | ADR 0001 names plugins.ts; the code is plugins/. A test catches this |
| 7 | Model-visible means logged, plus replay snapshots | DSH | Every input to a Petra prompt is a bus event; replays guard her replies |
| 8 | Model-surface test | dsh-superagent | Tool schemas and prompts checked against the glossary and a size budget |
| 9 | Validated config, loud failure | DSH | No hidden defaults |
| 10 | Steward, checkpoint and handoff note for long chats | DS-Bot | Petra's long chat: condense past 80% of the window, keep the user's messages word for word |
Does not fit. DSH and DS-Bot assume one long-lived process with local files and SQLite. A Durable Object hibernates, so plug-ins there must rebuild from stored state. Their hot reload watches files; tensquads swaps by bus message. DSH lets users patch composition; decision 18 forbids customer version pinning.
Not read. The cordis primer on DSH's docs site was blocked, so the cordis plug-in API itself is unverified here.
Bots studied: what to borrow #
The three products confirm the tensquads shape: one master that talks, specialists that work, approvals before risky actions. The ideas worth taking are about reliability, not features.
| Product | What it is | How it works |
|---|---|---|
| Rerun | Self-hosted "AI coworkers" | A Chief of Staff agent interviews the owner, plans a team and hires coworkers. Each agent is a folder of Markdown files: soul, skills, memory. Coworkers stop and ask before they send, pay or delete |
| OpenMausBot | Desktop group chat for agents | One local server owns every agent process and logs one event stream per thread. Risky actions become Allow / Deny cards. A cheap decision model routes messages |
| OpenBot | Workspace for persistent agents, desktop and hosted | An event log with projections. Each agent has a crash-safe queue. Workflows run as trigger, steps, approval |
Borrow
| # | Idea | From | Why it fits | Size |
|---|---|---|---|---|
| 2 | A routine skips its run if the last one is still active | OpenMausBot | Stops queue build-up on always-on machines | S |
| 3 | Boot reconcilers and a health check per machine | Rerun | Agents heal after a restart | S |
| 4 | Workflows shown as trigger, steps, approval | OpenBot | Maps directly onto the approval inbox | S |
| 5 | Job statuses: settled, needs user, failed, stalled, timed out | OpenMausBot | Petra gives the owner one honest status line | M |
| 6 | Squad templates install with everything off | OpenMausBot | Restaurant and grocer templates arrive paused and unapproved | M |
| 7 | Crash-safe queue per agent with pause, resume, cancel | OpenBot | A machine restart loses nothing | M |
| 8 | Onboarding interview that plans the squad | Rerun | Fits a non-technical owner; Petra already owns the conversation | M |
| 9 | After each run, a curator writes memory the owner can read | Rerun | The owner can see and correct what the squad learned | M |
| 10 | Append-only event log with projections | OpenBot, OpenMausBot | Audit and replay of what each agent did | L |
Do not borrow
OpenBot's agents run with full access and no per-action approval. This conflicts with the autonomy limits.
Rerun's agents can install their own tools and run an unconfined shell. An agent that grants itself tools bypasses the code check.
OpenMausBot lets many bots answer the user. In tensquads only Petra speaks.
OpenMausBot, a closer read. It is the nearest relative of tensquads: it runs bots on boat.dev cloud computers and uses Jev to route messages.
Routing with a decision model. A room set to Auto asks the model which bot should answer. It accepts the answer only above a 0.6 probability, a threshold measured against Jev. Every answer is validated before use.
It fails open. With no key, a timeout, an error or an unsure answer, the room does what it would have done without the model: the lead answers. In tensquads the lead is Petra.
Provider is swappable. Jev, Cloudflare Workers AI or OpenRouter sit behind one seam. tensquads already runs on Cloudflare, so Workers AI is a third Decider candidate.
A decision log. One row per call: seam, provider, choice, top probability, margin, latency, tokens and a hash of the state. No message text.
A live eval. 53 labelled messages replay against the live model for about $0.002 a run. This is the shape of the trial tensquads needs.
Triggers. Schedules, webhooks and app events ("when an email from Acme arrives") share one queued executor and one run history.
Teams as one Markdown file. A team installs from a file after a review screen. Connections stay off, routines arrive paused, and the file never carries keys, chats or memory.
Rerun, a closer read. Its pitch is the tensquads pitch: say what you need in plain words, and a Chief of Staff builds the team.
The Chief of Staff covers for the owner. It interviews the owner, hires the coworker for each job, and answers coworkers by the owner's rules while the owner is away. This is Petra plus the Rules screen.
Ready-made coworkers. Templates people hire on day one: inbox and calendar, data questions with a weekly KPI report, review and competitor watch with drafted replies, prospecting, social posts, and late-invoice chasing. Review watch fits Greenwich; invoice chasing fits the Accounting bot on the roadmap.
One board. Every coworker, every machine and every running task on one screen. Approvals appear inline in chat.
A screen you can watch. Each coworker has a browser the owner can watch and take over.
Each coworker is a folder. A soul file, skills, and a memory that grows with each task, all readable Markdown.
Architecture. One engine per workspace, with Postgres for data. The same shape as one Durable Object per account with Neon.
Not read. The OpenMausBot site redirects to a host this session cannot reach. Its findings come from its GitHub repository.
Memory #
What the references say
Anthropic: memory has four layers. Session transcripts are the base. Notes are what the agent chose to keep. Above them sit structures such as a wiki. On top is a small index loaded into every session. An offline pass ("dreaming") checks notes against transcripts and corrects them.
Anthropic's advice: store what the agent worked out, not what it can re-read. Record how each fact is known. Keep the top layer small. Give each record one writer: a shared table with many writers kept 41 of 57 facts; one page per contract with one writer kept 57 of 57.
OpenClaw: plain Markdown files, no hidden state. Owner preferences, curated facts and daily notes are separate files. Only the first two load at session start; the rest is reached by search. Search mixes keyword and vector, weighted by recency and importance. Every entry carries its origin, set by the system. Untrusted content can never be promoted. A nightly job is the only writer of the curated file.
Routing #
What OpenClaw does
Each agent has its own workspace, credentials and session store.
A binding maps an inbound message (channel, account, sender) to one agent. The most specific binding wins. Within a tier, the first in config order wins.
With no match, the message goes to a named fallback owner, or stays undispatched and is dead-lettered after 24 hours. Routing never picks the first agent in the list.
Bindings route inbound messages only. Delegation is the model's choice: a coordinator spawns specialists from an allow list.
Its team preset matches tensquads: the coordinator is the human's contact; specialists return work and do not delegate further.
Agent-to-agent access is open by default.
Decisions: Jev #
Speed and cost. These are the vendor's own numbers; we have not tested them.
| Jev | A large model | |
|---|---|---|
| Time for one judgement | 0.114 seconds | 8.566 seconds |
| Cost for one judgement | $0.000081 | $0.013880 |
TypeSafe says this example is "on the higher end of real world gains". It gives no accuracy number.
There are two candidates. Jev is from TypeSafe. Sage is from Levanto and does the same job. The Capacitr case study you sent is about Sage, not Jev. Capacitr put Sage in front of eight money-moving tools and reported under 100 ms per decision and no wrong blocks in 152 audited calls. Sage accepts Jev's request format, so we can test both with the same code.
Notes for builders
The
Deciderport takes one question and returns one answer. It needs an async form that takes several questions.Jev has four question types: Choice, Score, Noul (yes or no, as a probability) and Box (find something in an image). Sage has Yes/No, Choice, Scale, Sort and Tags, and returns
nullwhen unsure.Both use
POST /v1/systemone. Jev costs $0.042 per million input tokens; output is free.The Decider must fail safe. On an error, a timeout, or Sage's 402 when usage runs out, the task goes to Petra or the owner.
Jev 1.14's image, box and long-context features are experimental. Do not use them in production.
OpenMausBot accepts a Jev routing answer only above a 0.6 probability. It also supports Cloudflare Workers AI as a third provider.
Sources #
Framework
dsh-superagent-prototype: philosophy, domain, execution, architecture, cookbook
deepseek-harness: architecture, AGENTS.md, testing
cordis: core README
DS-Bot: AGENTS.md, README, and the steward, parts, groups and chat-index source files
Bots
Rerun: README, CLAUDE.md, engine README, INSTALL.md
OpenMausBot: AGENTS.md, team sharing, decision model, MCP server docs
OpenBot: home, teams, pricing, channels post, and its repository
Memory and routing
Components of agent memory, Anthropic
OpenClaw: memory, memory architecture, multi-agent
Decisions
TypeSafe: Don't call it a decision model, Jev 1.14, launch post, home
Levanto: Capacitr case study, pricing
Could not open
The OpenMausBot site (redirects to mausbot.com); its repository README and decision-model doc were read instead
The cordis primer on the DeepSeek Harness docs site
TypeSafe's docs and pricing, and Levanto's docs
Rerun's docs site
Also read: TypeSafe docs (introduction, models, confidence, index), Levanto docs (introduction, pricing, SystemOne API), and the full READMEs of Rerun and OpenMausBot.
14. Open questions #
Each question needs an answer before we build the related feature. When a question has an answer, the answer goes to Part 11, Decisions.
There are no open questions now.