Skip to content
Open
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
68 changes: 56 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,73 @@
# skillos

Implementation of Google's [SkillOS](https://arxiv.org/abs/2605.06614).
Implementation of Google's [SkillOS](https://arxiv.org/abs/2605.06614) — a framework for self-evolving agents.

Basically, it is a framework for self-evolving agents.
SkillOS lets agents record what they learn as structured skills and reuse them in future sessions. This repository is organized into a backend-agnostic core and SDK-specific integrations.

## Packages

- [`packages/skillos-core/`](packages/skillos-core/) — core abstractions
(`SkillRepo`, `Skill`, `Curator`, `AsyncCurator`). Backend-agnostic via fsspec.
- [`packages/skillos-strands/`](packages/skillos-strands/) — Strands Agents
analyzer for the Curator (Amazon Bedrock via `strands-agents`).
### Core

## Development
- [`skillos-core`](packages/skillos-core/) — interfaces and shared components: `SkillRepo`, `Skill`, `Curator`, `ConversationHistory`, `Changelog`. Backend-agnostic via [fsspec](https://filesystem-spec.readthedocs.io/).

### SDK Integrations

Pick the package that matches your agent framework:

| Package | Framework | Status |
|---------|-----------|--------|
| [`skillos-strands`](packages/skillos-strands/) | [Strands Agents](https://strandsagents.com) | Available |
| `skillos-adk` | [Google ADK](https://google.github.io/adk-docs/) | Coming soon |
| `skillos-langgraph` | [LangGraph](https://langchain-ai.github.io/langgraph/) | Coming soon |

## Getting Started

Choose the package for your agent framework and install it:

```bash
# Strands Agents (Amazon Bedrock)
pip install skillos-strands

# Google ADK (coming soon)
pip install skillos-adk

# LangGraph (coming soon)
pip install skillos-langgraph
```

All three share the same `SkillRepo` from `skillos-core` — the SDK package is just the bridge between your framework and the skill repository.

**Strands example — hook-based (automatic):**

This project uses [uv](https://docs.astral.sh/uv/) for environment and
dependency management. The Python version is pinned in `.python-version`
and resolved deps are locked in `uv.lock`.
```python
from skillos_core import SkillRepo
from skillos_strands import StrandsCurator
from strands import Agent
from strands.models import BedrockModel

repo = SkillRepo("./my-skills")
curator = StrandsCurator(repo, model=BedrockModel("us.amazon.nova-pro-v1:0"))

# Wire the curator as a hook — skills are updated automatically after every run
agent = Agent(
model=BedrockModel("us.amazon.nova-pro-v1:0"),
hooks=[curator.hook()],
)
await agent.invoke_async("What tools did you use for that task?")
```

## Development

This project uses [uv](https://docs.astral.sh/uv/) for environment and dependency management. The Python version is pinned in `.python-version` and resolved deps are locked in `uv.lock`.

```bash
uv sync # create .venv and install all workspace packages
uv run pytest # run the full test suite
```

To work on a single package, run pytest scoped to it:
To work on a single package:

```
```bash
uv run pytest packages/skillos-core
uv run pytest packages/skillos-strands
```
90 changes: 90 additions & 0 deletions docs/api/skillos-core.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,93 @@ Enum of common SPDX license identifiers. Accepts string coercion (`License("MIT"
| `MPL_2_0` | `MPL-2.0` |
| `AGPL_3_0` | `AGPL-3.0` |
| `UNLICENSE` | `Unlicense` |

---

## Curator

```python
from skillos_core import Curator
```

Abstract base class for all curator implementations. SDK-specific packages (`skillos-strands`, `skillos-adk`, `skillos-langgraph`) each provide a concrete subclass.

### `async curate(history: ConversationHistory) -> Changelog`

Analyse a conversation history and apply changes to the skill repository. Returns a `Changelog` recording what was inserted, updated, or deleted.

---

## ConversationHistory

```python
from skillos_core import ConversationHistory, Message
```

Type alias for the conversation passed to a curator.

```python
Message = dict[str, Any]
ConversationHistory = list[Message]
```

Each message is a dictionary with at minimum a `"role"` key (`"user"`, `"assistant"`) and a `"content"` key. The content may be a string or a list of content blocks (text, tool calls, tool results) depending on the agent framework.

---

## Changelog

```python
from skillos_core import Changelog
```

Record of mutations produced by a single curator run.

### Attributes

| Attribute | Type | Description |
|-----------|------|-------------|
| `changes` | `list[Change]` | All changes attempted (applied and failed). |
| `applied` | `list[Change]` | Changes that succeeded. |
| `failed` | `list[Change]` | Changes that raised an exception. |

---

## Change

```python
from skillos_core import Change, ChangeKind
```

A single mutation record within a `Changelog`.

### Attributes

| Attribute | Type | Description |
|-----------|------|-------------|
| `kind` | `ChangeKind` | `INSERT`, `UPDATE`, or `DELETE`. |
| `name` | `str` | Name of the affected skill. |
| `applied` | `bool` | `True` if the operation succeeded. |
| `error` | `str \| None` | Error message if the operation failed. |
| `description` | `str \| None` | New description (insert/update only). |
| `body` | `str \| None` | New body (insert/update only). |
| `license` | `License \| str \| None` | New license (insert/update only). |
| `allowed_tools` | `list[str] \| None` | New allowed tools (insert/update only). |
| `compatibility` | `str \| None` | New compatibility string (insert/update only). |
| `metadata` | `dict \| None` | New metadata (insert/update only). |

---

## ChangeKind

```python
from skillos_core import ChangeKind
```

Enum for the type of skill mutation.

| Member | Value |
|--------|-------|
| `INSERT` | `"insert"` |
| `UPDATE` | `"update"` |
| `DELETE` | `"delete"` |
120 changes: 120 additions & 0 deletions docs/api/skillos-strands.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# skillos-strands API Reference

`skillos-strands` implements the `Curator` interface for [Strands Agents](https://strandsagents.com) (Amazon Bedrock).

```bash
pip install skillos-strands
```

---

## StrandsCurator

```python
from skillos_strands import StrandsCurator
```

A `Curator` that runs a Strands `Agent` to analyse conversation history and mutate the skill repository. The agent receives a formatted history and calls skill tools (`list_skills`, `read_skill`, `insert_skill`, `update_skill`, `delete_skill`) to decide what to create, update, or delete.

### `StrandsCurator(repo, *, model, system_prompt=...)`

| Parameter | Type | Description |
|-----------|------|-------------|
| `repo` | `SkillRepo` | The skill repository to manage. |
| `model` | `strands.models.Model` | Any Strands-compatible model (e.g. `BedrockModel`). |
| `system_prompt` | `str` | Override the default curator system prompt. |

### `hook() -> HookProvider`

Return a Strands [`HookProvider`](https://strandsagents.com/latest/user-guide/concepts/hooks/) that automatically calls `curate()` after every agent invocation. Pass the result to `Agent(hooks=[...])` for zero-touch curation — no extra code in your run loop.

```python
from skillos_core import SkillRepo
from skillos_strands import StrandsCurator
from strands import Agent
from strands.models import BedrockModel

repo = SkillRepo("./my-skills")
curator = StrandsCurator(repo, model=BedrockModel("us.amazon.nova-pro-v1:0"))

agent = Agent(
model=BedrockModel("us.amazon.nova-pro-v1:0"),
hooks=[curator.hook()],
)

# Curation fires automatically after every invocation
await agent.invoke_async("Extract text from invoice.pdf")
```

The hook fires on `AfterInvocationEvent`. If the agent's message list is empty the hook is a no-op.

### `async curate(history: ConversationHistory) -> Changelog`

Format the conversation history, invoke the Strands agent, and return the resulting `Changelog`. Use this for manual control — e.g. when you receive history from an agent you don't own.

**Example:**

```python
from skillos_core import SkillRepo
from skillos_strands import StrandsCurator
from strands.models import BedrockModel

repo = SkillRepo("./my-skills")
curator = StrandsCurator(
repo,
model=BedrockModel("us.amazon.nova-pro-v1:0"),
)

changelog = await curator.curate(history)

for change in changelog.applied:
print(f"[{change.kind}] {change.name}")

for change in changelog.failed:
print(f"FAILED [{change.kind}] {change.name}: {change.error}")
```

---

## create_skill_tools

```python
from skillos_strands import create_skill_tools
```

Build the list of Strands tools for interacting with a `SkillRepo`. Use this directly when you want to embed skill-management capabilities into your own Strands agent rather than delegating to `StrandsCurator`.

### `create_skill_tools(repo, *, changelog=None) -> list[DecoratedFunctionTool]`

| Parameter | Type | Description |
|-----------|------|-------------|
| `repo` | `SkillRepo` | The skill repository to manage. |
| `changelog` | `Changelog \| None` | If provided, every mutation is recorded here. |

Returns five tools:

| Tool | Description |
|------|-------------|
| `list_skills` | List all skill names in the repository. |
| `read_skill` | Read a skill's metadata and body by name. |
| `insert_skill` | Create a new skill. |
| `update_skill` | Partially update an existing skill. |
| `delete_skill` | Delete a skill and all its bundled resources. |

**Example — embedding tools in your own agent:**

```python
from skillos_core import Changelog, SkillRepo
from skillos_strands import create_skill_tools
from strands import Agent
from strands.models import BedrockModel

repo = SkillRepo("./my-skills")
changelog = Changelog()
skill_tools = create_skill_tools(repo, changelog=changelog)

agent = Agent(
model=BedrockModel("us.amazon.nova-pro-v1:0"),
tools=[*your_other_tools, *skill_tools],
)
```
Loading