Seshat AIDocumentation

Documentation / Concepts

Skills and MCP

Two ways to extend the agent: skills teach it your rules, MCP servers give it new tools.

SkillsMCP servers
What they addInstructionsTools, resources and prompts
What they areA Markdown fileA program or a remote service
Good forYour conventions, checklists, workflowsGitHub, databases, Slack, anything with an API

Skills

A skill is a Markdown file with an optional YAML header. The agent has a skill tool whose description lists every skill by name and description. When a request matches one, the model calls the tool, receives the skill’s text as the tool result, and follows it.

Skill filesMarkdown files withan optional headerThe loaderproject, managed,user, builtin, reposThe skill toolits description listsevery skillThe modelreads the list andpicks a skillIt calls skillthe name and optionalargumentsThe tool looks it upfirst match in thepriority orderThe body comes backarguments filled in,as a tool resultThe model actsthe instructions guideits next steps
A skill is not injected into the system prompt. The model reads the list, asks for one, and receives its text as a tool result.
---
name: "summarise-pr"
description: "Summarise a GitHub pull request for the team. Use it when asked to summarise a PR or code review."
arguments: ["pr"]
---

Read the diff of ${pr} with the bash tool and write a short Markdown summary:
- what changed and why
- possible risks
- a checklist for the reviewer

The model decides from the description, so write it for the model: say what the skill does and when to use it.

Where skills live

The agent’s skill tool reads these folders. The runtime root is the runtime folder described in Configuration: ~/.config/seshat-cli for the seshat binary, ~/.config/seshat for a Go program using the SDK, unless you set SESHAT_RUNTIME_ROOT.

FolderScope
.claude/skills/ in the projectShared with your team when committed
.seshat/skills/ in the projectThe same, in Seshat’s own folder
.seshat/commands/ in the projectOlder command files, still read
.claude/skills/ in a sub-folder of the projectFound too, for a monorepo: up to 6 levels below the project root
<runtime root>/skills/user/Your personal skills
<runtime root>/skills/managed/Skills set by an administrator
<runtime root>/skills/builtin/A folder for built-in skills
<runtime root>/skills/repos/<name>/A cloned collection: each subfolder with a SKILL.md is a skill

When two skills have the same name, the first one found wins, in this order: project .claude/skills, project .seshat/skills, managed, user, builtin, older command files, sub-folder .claude/skills, collections, bundled skills. So a project skill overrides a personal one, and also an administrator’s.

1. Project .claude/skills/shared with your team2. Project .seshat/skills/the same, in the folder of Seshat3. Managed skillsset by an administrator4. User skillsyour personal skills5. Built-in skillsthe builtin folder6. Older command files.seshat/commands/ of the project7. .claude/skills/ in a sub-foldera monorepo, up to 6 levels below the project8. Collectionsskills/repos/<name>/ and the other folders of skills/9. Bundled skillscompiled into Seshat: the lowest priorityMOST SPECIFICLEAST SPECIFIC
When two skills have the same name, the first source in this list wins. A project skill overrides a personal one, and an administrator's.

Header fields

Not every field of the header does something yet. This table says what each one does today.

FieldEffect today
name, description, when_to_useListed by the skill tool, when_to_use next to the description. The model chooses from them
arguments, argument-hintarguments is a list of names (["pr"]) or a comma-separated string. ${name} or ${argument:name} in the body is replaced by the text the model passes. With one name, it gets the whole text. With several, the text is split on spaces by position and the last name gets the rest. Only names are read: a structured form with description and default is accepted, but the description and the default are not used
triggersPhrases shown next to the skill in the list, as a hint to the model
context: forkThe skill runs in an isolated sub-agent and its result comes back to the parent. allowed-tools and model apply to that sub-agent
agentAlso registers the skill as a sub-agent type: the body becomes its system prompt
allowed-tools, modelApply only to a sub-agent: a skill with context: fork or with agent. Ignored when the skill is called inline through the skill tool
effortSets the turns of the sub-agent type made by agent (see Agents and delegation)
shell.beforeThe commands are added to the skill’s text. The agent runs them with its shell tool, after asking permission
shell.after, on_error, on_complete, hooksRead but not run. For commands on events, use hooks
user-invocableUsed by the terminal interface to decide whether the skill appears as a command
disable-model-invocationThe terminal interface leaves the skill out of the list it gives the model
pathsNot applied by the skill tool. A Go host can filter skills by the files it works on with skills.GetSkillsForContext

The official collection is seshat-skills.

MCP servers

Model Context Protocol is an open standard for connecting agents to tools. Seshat is an MCP client: connect a server and its tools appear next to the built-in ones.

TransportForConfigure with
stdioA local program (npx, Python, a binary)Command, Args, Env
sseA remote serverURL, Headers
http (streamable)A remote serverURL, Headers

In Go

Seshat works out Transport when you leave it out: stdio when the server has a Command, http when it has a URL. Set it yourself for sse, which cannot be told apart from http by its fields. In Command, Args, URL, Env and Headers, ${VAR} is replaced by the value of that environment variable, and a variable that is not set produces a warning.

client, _ := sdk.NewClient(&sdk.ClientConfig{
    MCPServers: []sdk.MCPServerConfig{
        {
            Name:      "github",
            Transport: sdk.MCPTransportStdio,
            Command:   "npx",
            Args:      []string{"-y", "@modelcontextprotocol/server-github"},
            Env:       map[string]string{"GITHUB_PERSONAL_ACCESS_TOKEN": os.Getenv("GITHUB_TOKEN")},
        },
        {
            Name:      "remote",
            Transport: sdk.MCPTransportSSE,
            URL:       "https://my-mcp-server.example.com/sse",
            Headers:   map[string]string{"Authorization": "Bearer " + os.Getenv("MCP_TOKEN")},
        },
    },
})

What happens at runtime

ClientConfig.MCPServersone entry per serverCreatethe client and itstransportStartlaunch the processor reach the URLInitialisethe MCP handshakewith the serverWraptools, resourcesand promptsRegistermcp__server__toolin the tool registryThe agent sees one listbuilt-in tools andMCP tools togetherA call is routedto the server thatowns that toolThe result comes backas a normal toolresultIf a step fails for one server, that server is skipped and a line is logged.
Servers are connected one after another when the client is created. A server that fails at any step is skipped; the others carry on.
  1. For each configured server, in order, Seshat creates a client and starts it: a subprocess for stdio, a connection to the URL for the others.
  2. It runs the MCP handshake, then fetches the server’s tools, resources and prompts.
  3. The tools join the registry under the name mcp__<server>__<tool>. Resources and prompts are exposed as tools too.
  4. The agent sees one list of tools. Calls are routed to the server that owns the tool.
  5. When the client is closed, the subprocesses are stopped.

A server that cannot be created, started or initialised is skipped, and a line is written to the log. The client still starts, with the servers that worked, so check the log if a tool you expect is missing. You can change the servers while the client runs with client.ReloadMCPServers.

From a host application

A Go program that embeds Seshat can go further than the config file:

  • skills.RegisterAlias(alias, target) makes the skill tool accept alias as another name for target. Call it before the session starts: the registry is shared by the whole process and is not saved.
  • mcp.AddServer, mcp.RemoveServer and mcp.SetServerEnabled edit the MCP configuration files for you, so a settings screen does not have to write JSON by hand. AddServer checks the name (letters, digits, hyphens and underscores) and infers the transport when it is not set.

Updated on 2026-10-14