All notes
Engineering4 min read

Making agents harness-aware, Part 1

An agent should understand the product it runs inside, not just the messages in front of it.

A thin ivory rounded-square frame enclosing a sparse network of small ivory discs joined by thin lines, one disc solid orange near the center and one muted grey, on a charcoal ground

Bearly can now understand more of the product it runs inside. From a normal chat, it can find and read earlier conversations, create and organize chats, and find current Bearly documentation when someone asks about the product.

This is the first part of making agents harness-aware: giving one agent a clear view of its environment and careful control over it. Communication between agents is a separate problem, and the subject of Part 2.

The model is not the product

A language model sees messages and a set of available actions. The product around it has much more state: the current chat, other conversations, projects, files, memory settings, permissions, and controls that may not exist in every runtime.

That distinction shows up in ordinary requests:

Find the chat where we settled the onboarding plan, rename it “Customer onboarding,” and move it to the Operations project.

The words are easy to parse. The work is not. Bearly has to search the conversation memory available to the current chat, identify the source conversation, read enough of it to confirm the match, find the correct project, and make two changes to the right chat. It should do all of that without switching the conversation on the user's screen.

Titles are not enough. Two chats can have the same title, titles can change, and “this chat” means something specific. The harness therefore gives Bearly stable chat and project identities, and marks the conversation currently executing the request.

Context needs a shape

Giving an agent access to every conversation does not mean pouring every conversation into its context window.

Bearly starts with lean, paginated lists. When it reads a chat, the normal view includes the user's messages and the assistant's replies. Tool activity is available only when it is relevant. Older turns are read in pages, and the latest exchange is repeated on each page because it usually explains what the other chat is doing now.

Large conversations need another path. If a requested section is too large to return cleanly, Bearly adds the complete conversation as a Markdown file and returns a fitted portion inline. It can then read that file incrementally. The agent gets a useful answer immediately without pretending an unbounded transcript fits in one call.

Memory search and chat reading also remain separate. Memory finds likely conversations by meaning. Chat reading inspects the source. That separation lets a request move from “I remember discussing this somewhere” to the exact conversation without making fuzzy search responsible for the final answer.

Orientation cannot belong to the interface

Bearly does not always run behind a visible chat composer. Some tasks execute in a reduced or headless environment. If product identity and behavior live in the user-interface layer, removing the interface also removes the agent's orientation.

We moved that shared orientation into a small core that is present wherever a Bearly chat runs. It tells the agent which product it is in, how hidden product context should be treated, and where to find Bearly's current public documentation.

Other context stays with the capability that owns it. The Assets capability describes attached files. Chat Management describes conversations and projects. Optional capabilities can be disabled without making the remaining agent forget what it is.

The architecture follows one useful rule: the answer is not one giant system prompt. Each part of the harness explains the state and actions it is responsible for.

Control needs boundaries

Read access and destructive control should not feel the same.

Bearly can list, read, create, rename, and move chats as part of a request. Listing chats or reading a different chat asks for access, which you can grant for the current task session. Deleting a chat always opens a fresh confirmation that names the selected conversations and explains that their messages and chat-local files will be permanently removed. The chat executing the request cannot delete itself; the result would have nowhere reliable to land.

Managed teams can disable chat management altogether. The actions are also loaded only when they are relevant, keeping routine requests smaller and easier for the model to reason about.

The boundary this stops at

Everything here keeps one agent oriented inside its own environment: it can see the product around it and act within careful limits. It stops short of letting two Bearly chats work together. That boundary — how separate agents coordinate and hand off work — is where Part 2 picks up.