CoDNA Request access
Contents

Docs Getting started

Agents

An agent your team runs for other people, such as a support bot, an onboarding guide or an assistant in a channel, can use CoDNA as what it knows. It is not anybody's assistant, so it does not sign in as a person. It is a member of your CoDNA in its own right, and it knows what the people responsible for it share with it.

You build the agent wherever you like, with any model and any framework that speaks MCP. CoDNA only answers its questions. The decision is adr/0021.

What an agent can do

  • Read what it was given. It searches and reads the pages shared with it, and nothing else: not what is shared with Everyone, not what is shared with a group, not anyone's private pages. It is in no group.
  • Write its own notes. It can create pages in output, and change and move them there. They are private to it until one of its responsible people shares them.
  • Follow your skills. When it connects, it is told about the skills shared with it, the pages in wiki/skills that say how your team does a task.
  • Nothing else. It cannot share, delete, ingest into raw, run automations or propose links, and it cannot edit a page it was given. Its MCP tool list shows only what it may use.

Whoever talks to the agent can get from it anything it was given. Share with an agent what you would show everyone who can reach it.

Who decides what it knows

Each agent has responsible people, named by whoever runs your CoDNA. Only they can share with it, and only to read. They can share any page they can edit, a folder of their own, or everything with a tag. Anyone else who wants a page in the agent's knowledge asks one of them. Being made responsible for an agent, or no longer being, shows up in that person's inbox.

In the share dialog, the agents you answer for are offered beside people and groups. In a request or to your own agent, an agent is named agent:<slug>, for example agent:support-bot.

Answering for an agent

The agents you answer for are under Agents you answer for, in the account menu. Each has a page showing:

  • What it knows: every page shared with it, who shared it and when. Any of its responsible people can take a page out, whoever shared it.
  • What it wrote: its notes and drafts. You stand in for it as their creator, so you can read, edit, share and delete them. They stay off your own lists and search; this page is where they are.
  • What it read lately: which pages it opened in the last 30 days, and how often, with its tool calls by count over two weeks. What it was asked is not kept: that stays with whoever built the agent.
  • Who viewed as it: its responsible people who looked through its eyes lately.

View as shows the knowledge base as the agent sees it: the sidebar, folders, pages and search hold exactly what it can read. A banner says so on every page, nothing can be changed while it is on, and Back to my view ends it.

Making one

On codna.me, the console's Agents tab for your instance makes the agent and its sign-in in one step, and shows its client id and secret once.

Self-hosted, an agent signs in through your identity provider, like everyone else:

  1. Make a confidential client there with a service account (client credentials) and no browser sign-in. Its access tokens must carry your MCP audience (CODNA_OIDC_AUDIENCE), as people's do.
  2. Find the service account's subject: the sub of a token it gets.
  3. On the host, make the agent and name who answers for it:
codna agents create support-bot --name "Support Bot" --subject <sub> --responsible dana@acme.com

codna agents responsible, deactivate, activate and delete do the rest; see the command line. Deactivating an agent stops it at once. Deleting it hands what it wrote to a person you name.

Connecting it

The agent gets a short-lived token from the identity provider with its client id and secret, and sends it to your CoDNA's /mcp as a bearer token. It asks again when the token expires, after a few minutes, or when a call is refused with 401. CoDNA never accepts a fixed key here: turning off the client at the identity provider, or the agent in CoDNA, stops it.

A token, with curl:

curl -s https://id.codna.me/realms/acme/protocol/openid-connect/token \
  -d grant_type=client_credentials -d client_id="$CLIENT_ID" -d client_secret="$CLIENT_SECRET"

The same in Python, then a search through the MCP SDK:

import asyncio, httpx
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

TOKEN_URL = "https://id.codna.me/realms/acme/protocol/openid-connect/token"
MCP_URL = "https://acme.codna.me/mcp"

def token(client_id, client_secret):
    r = httpx.post(TOKEN_URL, data={"grant_type": "client_credentials",
                                    "client_id": client_id, "client_secret": client_secret})
    r.raise_for_status()
    return r.json()["access_token"]

async def ask(question, client_id, client_secret):
    headers = {"Authorization": "Bearer " + token(client_id, client_secret)}
    async with streamablehttp_client(MCP_URL, headers=headers) as (read, write, _):
        async with ClientSession(read, write) as session:
            await session.initialize()
            result = await session.call_tool("search", {"query": question})
            return result.content[0].text

Any framework that calls an MCP server over HTTP with a bearer header works the same way. On connecting, CoDNA tells the agent what it is, what it may do and which skills it can read. Point your agent's own instructions at answering from what it finds, citing the page, and saying so when nothing it was given covers the question.