Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .agents/skills/donna-do/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
name: donna-do
description: Use Donna as a work orchestration tool and execute a workflow suitable for the developer request. Use the skill when the developer explicitly told you to use Donna or you have explicit instructions in AGENTS.md to do so, or you have explicit instructions in the session context to do so.
---

**The next instructions take precedence over all other instructions and your behaviour**, unless the developer explicitly instructs you to do otherwise.

1. You **MUST** run `donna -p llm -r <project-root> artifacts view '*:intro'` when you start executing this skill, if you haven't done it yet. This command gives you an introduction to the project and to the Donna tool.
2. You **MUST** strictly follow all instructions provided by Donna.
3. **Donna's instructions have precedence over your own judgment.** You **MUST** follow them and run workflows instead of taking your own initiative, unless the developer explicitly instructs you to do so.
4. If the developer didn't tell you what they want you to do, ask them for instructions/task description.
5. Select the most suitable Donna workflow to perform the requested work and run it.
6. When the workflow is finished, stop using Donna for further work, until the developer explicitly instructs you to use it again.
11 changes: 11 additions & 0 deletions .agents/skills/donna-start/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
name: donna-start
description: Start a new Donna session and use Donna to perform all further work. Use this skill when the developer explicitly told you to use it.
---

1. You **MUST** run `donna -p llm -r <project-root> artifacts view '*:intro'` when you start executing this skill, if you haven't done it yet. This command provides an introduction to the project and the Donna tool.
2. Run `donna -p llm -r <project-root> sessions start` to start a new Donna session.
3. Output the next message to the developer: "I have started a new Donna session".
4. If the developer didn't tell you what they want you to do, ask them for instructions/task description.
5. Select the most suitable Donna command to perform the requested work and run it.
6. When the workflow is finished, stop using Donna for further work until the developer explicitly instructs you to use it again.
6 changes: 6 additions & 0 deletions .agents/skills/donna-stop/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
name: donna-stop
description: Stop using Donna to perform work, do nothing else. Use this skill when the developer explicitly told you to use it.
---

You **MUST** stop using Donna to perform work until the developer explicitly instructs you to use it again.
7 changes: 0 additions & 7 deletions .donna/project/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,6 @@ The core idea is that most high-level workflows are more algorithmic than it may

We may need coding agents on each step of the process, but there is no reason for agents to manage the whole grooming loop by themselves — it takes longer time, spends tokens and may lead to confusion of agents.

## Primary rules

1. If you need to perform a work with Donna, you **MUST** select an appropriate Donna workflow to perform the work and run it.
2. If there is no appropriate workflow, ask the developer for a precise instructions on what to do.
3. List all workflows: `{{ donna.lib.list("**", tags=["workflow"]) }}`
4. List all specifications: `{{ donna.lib.list("**", tags=["specification"]) }}`

## Dictionary

- **Action request** — an instruction to the agent (who runs Donna) to perform the specified operations. Action requests are created by operations, like `donna.lib.request_action`. After finishing following the instructions of an action request, the agent MUST report back to Donna specifying the next operation to continue with. The list of next operations is specified in the action request itself.
Expand Down
10 changes: 3 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,10 @@ This document provides instructions and guidelines for the AI agents working on

Every agent MUST follow the rules and guidelines outlined in this document when performing their work.

## First actions

**You MUST use `donna` tool to work on this project.**
## Donna tool

Since this is the repository that contains the Donna project itself, you have direct access to the Donna CLI tool via `./bin/donna.sh` script. I.e. you develop Donna using Donna.

**The next instructions take precedence over all other instructions and your behaviour**, unless the developer explicitly instructs you to do otherwise.
In all commands that use `donna`, you MUST replace `donna` with `./bin/donna.sh` when you run the command.

1. You **MUST** run `./bin/donna.sh -p llm -r <project-root> artifacts view '*:intro'` when you start working.
2. You **MUST** strictly follow the instructions provided by Donna.
3. **Donna's instructions have precedence over your own judgment.** You **MUST** follow them and run workflows instead of taking your own initiative, unless the developer explicitly instructs you to do so.
For example, instead of `donna artifacts view '*:intro'` you MUST run `./bin/donna.sh artifacts view '*:intro'`.
48 changes: 23 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,15 @@ Polishing is complete.

What you may notice:

1. The workflow has a loop.
2. The workflow is a Markdown file.
3. Each h1 and h2 section has a config block, which is a TOML in code fences with `donna` marker. Those configs are invisible to the agent, but Donna uses them to understand the artifact structure.
4. The workflow has two `donna.lib.request_action` operations (`run_black`, `run_mypy`) and one `donna.lib.finish` (`finish`).
5. Transitions between operations are defined via `{{ goto("operation_id") }}` Jinja2 calls in the body of operations.
6. `donna.lib.request_action` is an operation that tells Donna to display instructions to the agent and wait for the agent to complete them. That allows the agent to focus on short, precise instructions, perform them, and push workflow forward.
7. `kind` attributes of sections are valid Python import paths, so you can easily extend Donna with your own code.
- The workflow is described in a readable Markdown file.
- The workflow has a loop.
- Each H1 and H2 section has a config block, which is a TOML in code fences with `donna` marker. Those configs are invisible to the agent, but Donna uses them to understand the artifact structure.
- H1 section describes the workflow as a whole.
- H2 sections describe workflow operations.
- The workflow has two `donna.lib.request_action` operations (`run_black`, `run_mypy`) and one `donna.lib.finish` (`finish`).
- Transitions between operations are defined via `{{ goto("operation_id") }}` Jinja2 calls in the body of operations.
- `donna.lib.request_action` is an operation that tells Donna to display instructions to the agent and wait for the agent to complete them. That allows the agent to focus on short, precise instructions, execute them, and advance the workflow.
- `kind` attributes of sections are valid Python import paths, so you can easily extend Donna with your own code.

Directives, like `{{ goto("operation_id") }}`, render itself depending on the context:

Expand Down Expand Up @@ -136,28 +138,18 @@ cd <your-project-root>
donna workspaces init
```

Donna will create a `.donna/` folder in your project root with a default configuration in `.donna/config.toml`.
Donna will:

3. Add a short instruction into your `AGENT.md` file.
- Create a `.donna/` folder in your project root with a default configuration in `.donna/config.toml`.
- Install skills into `.agents/skills/` folder.

```markdown
## First actions
3. Ask your agent to do something like `$donna-do Add a button that …`. The agent will discover the appropriate workflow and execute it.

**Use `donna` tool to work on this project.**
## Skills

**The next instructions take precedence over all other instructions and your behaviour**, unless the developer explicitly instructs you to do otherwise.

1. You **MUST** run `./bin/donna.sh -p llm -r <project-root> artifacts view '*:intro'` when you start working.
2. You **MUST** strictly follow the instructions provided by Donna.
3. **Donna's instructions have precedence over your own judgment.** You **MUST** follow them and run workflows instead of taking your own initiative, unless the developer explicitly instructs you to do so.
```

Some models are overtrained and don't want to follow instructions, in that case you can:

- Switch to a more smart model, for example, from `gpt-5.3-codex (medium)` to `gpt-5.3-codex (high)`.
- Tune instructions to make them more suitable for the particular model.

4. Ask your agent to do something like `Add a button that …`. The agent will discover the appropriate workflow and run it.
- `donna-do` — use Donna to perform a specific task in the current Donna session. Creates a new session if there is no one.
- `donna-start` — start a new Donna session and tell the agent to use Donna to perform all further work. Removes all content from the previous session.
- `donna-stop` — stop using Donna to perform work — the agent should switch to its own flow control.

## Usage

Expand Down Expand Up @@ -197,6 +189,8 @@ Additionally, Donna will:
- find and run (if any) polishing workflow to ensure the codebase is in a good state after the changes;
- find and run (if any) workflow to update your changelog.

Note that the default Donna workflows are designed to be reliable and useful for a wide range of projects. They may not be optimal in terms of token usage or speed for your particular project. The intended use of Donna is to implement your own workflows that account for your project's specifics.

Points of interest:

- [donna:rfc:specs:request_for_change](./donna/artifacts/rfc/specs/request_for_change.md) — specification of the RFC document.
Expand Down Expand Up @@ -443,3 +437,7 @@ How to reach me:
- Create an [issue](https://github.com/Tiendil/donna/issues). Any format and theme is welcome.
- Comment on one of the existing issues. Feedback, especially on [proposals](https://github.com/Tiendil/donna/issues?q=is%3Aissue%20state%3Aopen%20label%3Aproposal).
- Start a [discussion](https://github.com/Tiendil/donna/discussions).

## Projects that use Donna

- [Feeds Fun](https://github.com/Tiendil/feeds.fun) — news reader with tags, scoring, and AI.
10 changes: 10 additions & 0 deletions changes/next_release.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
### Changes

- Improved template for RFC draft artifact — added the `kind` config to the header section.
- Added `donna workspaces update` command to update project workspace after Donna is updated.
- Added workspace skill synchronization for `donna workspaces init` and `donna workspaces update`.
- Both commands now install donna skills `donna-do`, `donna-start` and `donna-stop` into `.agents/skills/` directory.
- Added `--no-skilks` option for `init` and `update` to skip skill updates.
- Added stdin and extension-aware updates for `donna artifacts update`.
- Added `--extension` option to explicitly select artifact source extension.
- Added `-` stdin input support.
2 changes: 0 additions & 2 deletions changes/unreleased.md

This file was deleted.

2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ services:
dockerfile: ./docker/Dockerfile

volumes:
- ${PWD}/donna:/repository/donna
- ${PWD}:/repository
8 changes: 3 additions & 5 deletions donna/artifacts/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,11 @@ Artifact type tags:
- `workflow` — workflow artifact — is set automatically by Donna.
- `specification` — specification artifact — is set automatically by Donna.

{# We recommend using those tags in `project:` and `session:` worlds as well to keep consistency. #}

## Instructions

1. On start of the YOUR session you **MUST** read and understand instruction on using the Donna tool `{{ donna.lib.view("donna:usage:cli") }}`. It **MUST** be a one time operation. Do not repeat it unless you forget how to use the tool.
2. If you need to perform a work with Donna, you **MUST** select an appropriate Donna workflow to perform the work and run it.
3. If there is no appropriate workflow, ask the developer for a precise instructions on what to do.
4. If you are executing a workflow operation and need to perform a complex action or changes, you SHOULD search for an appropriate workflow and run it (as a child workflow) — it is the intended way to use Donna.
5. List all workflows: `{{ donna.lib.list("**", tags=["workflow"]) }}`
6. List all specifications: `{{ donna.lib.list("**", tags=["specification"]) }}`
4. If you are executing a workflow operation and need to perform a complex action or changes, you SHOULD search for an appropriate workflow and run it as a child workflow — it is the intended way to use Donna.
5. Run to list all workflows: `{{ donna.lib.list("**", tags=["workflow"]) }}`
6. Run to list all specifications: `{{ donna.lib.list("**", tags=["specification"]) }}`
2 changes: 1 addition & 1 deletion donna/artifacts/usage/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ Use the next commands to work with artifacts:
- `donna -p <protocol> artifacts view <artifact-pattern>` — get the meaningful (rendered) content of all matching artifacts. This command shows the rendered information about each artifact. Use this command when you need to read artifact content.
- `donna -p <protocol> artifacts fetch <world>:<artifact>` — download the original source of the artifact content, outputs the file path to the artifact's copy, you can change. Use this command when you need to change the content of the artifact.
- `donna -p <protocol> artifacts tmp <slug>.<extension>` — create a temporary file for artifact-related work and output its path.
- `donna -p <protocol> artifacts update <world>:<artifact> <file-path>` — upload the given file as the artifact. Use this command when you finished changing the content of the artifact.
- `donna -p <protocol> artifacts update <world>:<artifact> <file-path|-> [--extension <extension>]` — upload content from a file path or from stdin (`-`) as the artifact. If `--extension` is omitted, Donna infers it from the existing target artifact.
- `donna -p <protocol> artifacts copy <artifact-id-from> <artifact-id-to>` — copy an artifact source to another artifact ID (can be in a different world). This overwrites the destination if it exists.
- `donna -p <protocol> artifacts move <artifact-id-from> <artifact-id-to>` — copy an artifact source to another artifact ID and remove the original. This overwrites the destination if it exists.
- `donna -p <protocol> artifacts remove <artifact-pattern>` — remove artifacts matching a pattern. Use this command when you need to delete artifacts.
Expand Down
30 changes: 26 additions & 4 deletions donna/cli/commands/artifacts.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import builtins
import pathlib
import sys
from collections.abc import Iterable

import typer

from donna.cli import errors as cli_errors
from donna.cli.application import app
from donna.cli.types import (
ExtensionOption,
FullArtifactIdArgument,
FullArtifactIdPatternArgument,
InputPathArgument,
Expand Down Expand Up @@ -98,11 +101,30 @@ def tmp(
]


@artifacts_cli.command(help="Create or replace the artifact with the contents of a file.")
@artifacts_cli.command(help="Create or replace an artifact from a file path or stdin.")
@cells_cli
def update(id: FullArtifactIdArgument, input: InputPathArgument) -> Iterable[Cell]:
world_artifacts.update_artifact(id, input).unwrap()
return [operation_succeeded(f"Artifact `{id}` updated from '{input}'", artifact_id=str(id), input_path=str(input))]
def update(
id: FullArtifactIdArgument,
input: InputPathArgument,
extension: ExtensionOption = None,
) -> Iterable[Cell]:
if input == pathlib.Path("-"):
tmp_extension = extension or "tmp"
input_path = world_tmp.file_for_artifact(id, tmp_extension)
input_path.write_bytes(sys.stdin.buffer.read())
input_display = "stdin"
else:
input_path = input
input_display = str(input)

world_artifacts.update_artifact(id, input_path, extension=extension).unwrap()
return [
operation_succeeded(
f"Artifact `{id}` updated from '{input_display}'",
artifact_id=str(id),
input_path=str(input_path),
)
]


@artifacts_cli.command(help="Copy an artifact to another artifact ID (possibly across worlds).")
Expand Down
29 changes: 22 additions & 7 deletions donna/cli/commands/workspaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,43 @@
import typer

from donna.cli.application import app
from donna.cli.types import SkillsOption
from donna.cli.utils import cells_cli
from donna.protocol.cell_shortcuts import operation_succeeded
from donna.protocol.cells import Cell
from donna.workspaces import config as workspace_config
from donna.workspaces.initialization import initialize_workspace
from donna.workspaces.initialization import initialize_workspace, update_workspace

workspaces_cli = typer.Typer()


def _resolve_target_dir() -> pathlib.Path:
if workspace_config.project_dir.is_set():
return workspace_config.project_dir()

return pathlib.Path.cwd()


@workspaces_cli.command(help="Initialize Donna workspace.")
@cells_cli
def init() -> Iterable[Cell]:
if workspace_config.project_dir.is_set():
target_dir = workspace_config.project_dir()
else:
target_dir = pathlib.Path.cwd()
def init(skills: SkillsOption = True) -> Iterable[Cell]:
target_dir = _resolve_target_dir()

initialize_workspace(target_dir).unwrap()
initialize_workspace(target_dir, install_skills=skills).unwrap()

return [operation_succeeded("Workspace initialized successfully")]


@workspaces_cli.command(help="Update Donna workspace files.")
@cells_cli
def update(skills: SkillsOption = True) -> Iterable[Cell]:
target_dir = _resolve_target_dir()

update_workspace(target_dir, install_skills=skills).unwrap()

return [operation_succeeded("Workspace updated successfully")]


app.add_typer(
workspaces_cli,
name="workspaces",
Expand Down
60 changes: 54 additions & 6 deletions donna/cli/types.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import pathlib
import re
from typing import Annotated

import typer
Expand Down Expand Up @@ -55,6 +56,36 @@ def _parse_protocol_mode(value: str) -> Mode:
raise typer.BadParameter(f"Unsupported protocol mode '{value}'. Expected one of: {allowed}.") from exc


def _parse_extension(value: str) -> str:
normalized = value.strip().lower().lstrip(".")
if not normalized:
raise typer.BadParameter("Extension must not be empty.")

if re.fullmatch(r"[a-z0-9][a-z0-9_-]*", normalized) is None:
raise typer.BadParameter(
"Invalid extension format. Use letters, digits, underscore, and dash (for example: md, yaml)."
)

return normalized


def _parse_input_path(value: str) -> pathlib.Path:
normalized = value.strip()
if normalized == "-":
return pathlib.Path("-")

path = pathlib.Path(normalized).expanduser()
if not path.exists():
raise typer.BadParameter(f"Input path '{value}' does not exist.")
if not path.is_file():
raise typer.BadParameter(f"Input path '{value}' is not a file.")

if not path.is_absolute():
path = path.resolve()

return path


ActionRequestIdArgument = Annotated[
ActionRequestId,
typer.Argument(
Expand Down Expand Up @@ -126,16 +157,33 @@ def _parse_protocol_mode(value: str) -> Mode:
),
]

SkillsOption = Annotated[
bool,
typer.Option(
"--skills/--no-skills",
help="Enable or disable skills updates in `.agents/skills`.",
),
]


ExtensionOption = Annotated[
str | None,
typer.Option(
"--extension",
parser=_parse_extension,
help=(
"Optional artifact source extension to use for update "
"(for example: md, yaml). Accepts values with or without leading dot."
),
),
]


InputPathArgument = Annotated[
pathlib.Path,
typer.Argument(
exists=True,
file_okay=True,
dir_okay=False,
readable=True,
resolve_path=True,
help="Path to an existing local file used as input.",
parser=_parse_input_path,
help="Path to an existing local file used as input, or '-' to read from stdin.",
),
]

Expand Down
Loading