# Project files

A Maitento project is a folder of small text files. Each kind of definition has its own folder, and the file name
is the definition's name. This reference lists every kind of file and every property it can set. It is generated
from Maitento's code, so it matches what a deploy accepts. The same description is published as
[`sdks/mtr-schema.json`](https://github.com/maitento/maitento/blob/main/sdks/mtr-schema.json) for tools, and drives the
[VS Code extension](https://github.com/maitento/maitento/tree/main/editors/vscode).

## The folder

```text
<project>/
├── agents/                             agents (.mtr)
├── interactions/
│   ├── one-shot/                       one-shot interactions (.mtr)
│   ├── round-robin/                    round-robin interactions (.mtr)
│   └── managed/                        managed interactions (.mtr)
├── connectors/
│   └── open-api/                       connectors (.mtr)
├── external-operations/
│   └── open-api/                       tools (.mtr)
├── capsules/                           capsules (.mtr)
├── looms/                              looms (.mtr)
├── apps/
│   └── <name>/                         app settings (.mtr, optional); app code (*.mtc)
├── prompts/                            prompt files (*.md)
├── json/                               JSON files (*.json)
├── code-pipelines/
│   └── <name>/                         pipeline-definition.json
└── code-pipeline-hooks/
    └── <name>/                         code pipeline hooks (*.mtc)
```

Sub-folders inside a kind's folder are fine. Anything else in the project, such as a README, is ignored.

| Folder | What a file there defines | Reference |
|---|---|---|
| `agents/` | An agent: a model with standing instructions, a one-line summary and the tools it may use. | [Agents](https://docs.maitento.com/reference/project-files/agents.md) |
| `interactions/one-shot/` | A one-shot interaction: one agent, one task, one answer. | [One-shot interactions](https://docs.maitento.com/reference/project-files/interactions-one-shot.md) |
| `interactions/round-robin/` | A round-robin interaction: agents, and optionally a person, take turns in one shared conversation. | [Round-robin interactions](https://docs.maitento.com/reference/project-files/interactions-round-robin.md) |
| `interactions/managed/` | A managed interaction: a manager agent owns the task and hands pieces of work to named team members, who see only what the manager sends them. | [Managed interactions](https://docs.maitento.com/reference/project-files/interactions-managed.md) |
| `connectors/open-api/` | A connector: one HTTP endpoint, described once. | [Connectors](https://docs.maitento.com/reference/project-files/connectors.md) |
| `external-operations/open-api/` | A tool: what an agent sees and calls. | [Tools](https://docs.maitento.com/reference/project-files/tools.md) |
| `capsules/` | A capsule: the recipe for a short-lived Linux sandbox. | [Capsules](https://docs.maitento.com/reference/project-files/capsules.md) |
| `looms/` | A named loom: a long-term memory several interactions can share. | [Looms](https://docs.maitento.com/reference/project-files/looms.md) |
| `apps/<name>/` | An app's settings: the optional `.mtr` file beside an app's Cogniscript (`.mtc`) code. | [App settings](https://docs.maitento.com/reference/project-files/apps.md) |

Tools are known in Maitento as external operations (extops), which is why their folder is
`external-operations/open-api/`.

## A small project

The [02-prompts-and-inputs](https://github.com/maitento/maitento/tree/main/examples/02-prompts-and-inputs) example: an agent, an interaction that puts it to work, and the two
prompt files they include.

```hcl title="agents/poet.mtr"
model = @ref("deepseek.deepseek-v4-flash")
prompt = @prompt("poet")
summary = "A poet who writes short poems"
```

```hcl title="interactions/one-shot/haiku.mtr"
agent = {
  name = "Poet"
  agent = @ref("poet")
}
task = @prompt("haiku-task")
inputs.prompts = [
  {
    name = "topic"
    description = "What the haiku is about"
    required = true
  },
  {
    name = "mood"
    description = "Optional mood, for example calm or playful"
    required = false
  }
]
```

```md title="prompts/haiku-task.md"
Write a haiku about %%topic%%.
{{#if mood}}
The mood of the haiku should be %%mood%%.
{{/if}}
```

```md title="prompts/poet.md"
You are a poet who writes short, vivid poems.
You only ever reply with the poem itself: no title, no explanation.
```

## Writing `.mtr` files

One `name = value` per line. Comments start with `//`.

### Values

| Written | Example | Meaning |
|---|---|---|
| `"text"` | `"You are a friendly assistant."` | Text in double quotes, taken exactly as written: `\n` stays a backslash and an `n`, and the text may run over several lines. Put anything long in a prompt file and use `@prompt("name")`. |
| `123 or 0.5` | `0.85` | A number, without quotes. |
| `true or false` | `true` | `true` or `false`, without quotes. |
| `{ name = value ... }` | `agent = { name = "Greeter" agent = @ref("greeter") }` | A block of properties in braces, one `name = value` after another, with no commas. |
| `[ value, value ]` | `packages = ["git", "curl"]` | A list in square brackets with commas between the items. A list cannot be empty: leave the property out instead. |

### References

A property that names another definition takes a reference. Each property's entry says what it must name.

| Form | Means |
|---|---|
| `@ref("name")` | Another definition, by name, in the namespace you deploy to. It may be declared in the same project, or already exist. |
| `@ref("name", "namespace")` | A definition in another namespace. |
| `@ref(id)` | A definition by its id, without quotes. |

### Including a file

| Form | Reads | Means |
|---|---|---|
| `@prompt("name")` | `prompts/<name>.md` | The text of a prompt file, as the value of a text property. It cannot be an item of a list. |
| `@json("name")` | `json/<name>.json` | The text of a JSON file, as the value of a text property, usually a JSON Schema. It cannot be an item of a list. |

### Maps

A map property takes one line per entry: the property's name, a colon and the key, then the value as text.

```hcl
bindings.query:units = "metric"
```

### Inputs in text

In an interaction's task, and in the prompt files it includes, `%%name%%` is replaced by the run's input `name`. `{{#if name}}...{{/if}}` keeps its text only when the input has a value, and `{{#unless name}}...{{/unless}}` only when it has none. Every block must be closed.

### Rules that catch people out

- **Put spaces around `=`.** Without them, the name, the `=` and the value read as one word.

  Wrong: `summary="A friendly assistant"`  
  Right: `summary = "A friendly assistant"`

- **A name with dots is one name.** `inputs.prompts` is written as it is, never as a block named `inputs`.

  Wrong: `inputs = { prompts = [ { name = "topic" } ] }`  
  Right: `inputs.prompts = [ { name = "topic" } ]`

- **A block holds `name = value` entries with no commas between them.** Lists have commas.

  Wrong: `agent = { name = "Greeter", agent = @ref("greeter") }`  
  Right: `agent = { name = "Greeter" agent = @ref("greeter") }`

- **A list cannot be empty.** Leave the property out instead.

  Wrong: `functions = []`  
  Right: `// no functions`

- **Numbers and `true` / `false` have no quotes, and text always has them.**

  Wrong: `allowWebSearch = "true"`  
  Right: `allowWebSearch = true`

- **Set each property once in a file, and once in each block.**

  Wrong: `summary = "A" summary = "B"`  
  Right: `summary = "B"`

- **`@prompt` and `@json` give the value of a text property.** They cannot be items of a list.

  Wrong: `prompts.system = [ @prompt("house-style") ]`  
  Right: `prompts.system = [ "Write in British English." ]`

- **A file needs at least one property or comment: an empty file does not build.**

  Right: `// Settings for this app: none yet.`

### Names

A resource's name is its file name without `.mtr` (an app's is its folder's name). Use letters, digits, `_`, `-` and `.` (but not `..`), at most 128 characters. Two files of the same kind may not have the same name, even in different sub-folders or with different capitals.

## Other files

### Prompt file

Text for any text property, included with `@prompt("name")`: `prompts/name.md`, in any sub-folder of `prompts/`. A file is found by its name alone, so keep names unique. The text may use the run's inputs as `%%name%%`, and `{{#if name}}...{{/if}}` / `{{#unless name}}...{{/unless}}` blocks, which must be balanced.

### JSON file

JSON, usually a JSON Schema, included with `@json("name")`: `json/name.json`, in any sub-folder of `json/`. A file is found by its name alone, so keep names unique.

### App code

An app's program, in Cogniscript: `apps/<app>/*.mtc`, at least one per app (an app folder without one is skipped). The program starts at `main`, and `main`'s parameters are the app's inputs. An optional `.mtr` beside it holds the app's settings.

### Code pipeline definition

A code pipeline: `code-pipelines/<pipeline>/pipeline-definition.json`. Its `name` must be the folder's name. A pipeline folder without the file is skipped.

| Include | Reads | Means |
|---|---|---|
| `"@prompt(name)"` | `code-pipelines/<pipeline>/prompts/<name>.md` | Replaced by the text of the pipeline's own prompt file, as a JSON string. A missing file fails the whole build. |
| `"@schema(name)"` | `code-pipelines/<pipeline>/<name>.schema.json` | Replaced by the text of the pipeline's schema file, as a JSON string. A missing file fails the whole build. |
| `"@externalOp(namespace/name)"` | `<namespace>/<tool>` | Replaced by the id of a tool, which may be declared in the same project. |

### Code pipeline hook

Cogniscript functions a code pipeline runs between its phases: `code-pipeline-hooks/<pipeline>/*.mtc`. Every top-level function is `string Name(string processId, string methodName)`.

| Include | Reads | Means |
|---|---|---|
| `@promptJson(pipeline/name)` | `code-pipelines/<pipeline>/prompts/<name>.md` | Inside a string literal: replaced by the prompt file's text, escaped for a JSON string. |
| `@schemaJson(pipeline/name)` | `code-pipelines/<pipeline>/<name>.schema.json` | Inside a string literal: replaced by the schema file's text, escaped for a JSON string. |

## The files, kind by kind

- [Agent files](https://docs.maitento.com/reference/project-files/agents.md): An agent: a model with standing instructions, a one-line summary and the tools it may use.
- [One-shot interaction files](https://docs.maitento.com/reference/project-files/interactions-one-shot.md): A one-shot interaction: one agent, one task, one answer.
- [Round-robin interaction files](https://docs.maitento.com/reference/project-files/interactions-round-robin.md): A round-robin interaction: agents, and optionally a person, take turns in one shared conversation.
- [Managed interaction files](https://docs.maitento.com/reference/project-files/interactions-managed.md): A managed interaction: a manager agent owns the task and hands pieces of work to named team members, who see only what the manager sends them.
- [Connector files](https://docs.maitento.com/reference/project-files/connectors.md): A connector: one HTTP endpoint, described once.
- [Tool files](https://docs.maitento.com/reference/project-files/tools.md): A tool: what an agent sees and calls.
- [Capsule files](https://docs.maitento.com/reference/project-files/capsules.md): A capsule: the recipe for a short-lived Linux sandbox.
- [Loom files](https://docs.maitento.com/reference/project-files/looms.md): A named loom: a long-term memory several interactions can share.
- [App settings files](https://docs.maitento.com/reference/project-files/apps.md): An app's settings: the optional `.mtr` file beside an app's Cogniscript (`.mtc`) code.
