diff --git a/README.md b/README.md
index 57fcb2d..408a5b4 100644
--- a/README.md
+++ b/README.md
@@ -35,6 +35,7 @@
- **User Profile & Identity**: Name and background provided at session start; agents treat the user as an equal room participant.
- **Global Orchestrator**: A designated room moderator that fires every N turns to summarize or redirect agents, with no runaway loop risk.
- **Timestamped Session Memory**: All turns, messages, and system events are tagged with precise timestamps for full auditability.
+- **Optional Skillware Integration**: Assign skills per agent, execute tools lazily, and keep user-facing replies natural.
## Framework Capabilities
@@ -54,9 +55,10 @@ The framework allows extreme granularity in handling session configurations:
For deeper insights into how to leverage and modify the framework, please refer to our dedicated documentation guides:
-- [Architecture & LiteLLM Guide](docs/ARCHITECTURE.md) - Understand how local API routing, session memory, and agent selection work.
+- [Architecture & LiteLLM Guide](docs/ARCHITECTURE.md) - Understand local API routing, session memory, orchestration, and tool logging.
- [Use Cases, Examples & Best Practices](docs/EXAMPLES.md) - Parameter cheat sheet, deep persona guide, scenario walkthroughs, and an edge case reference table.
-- [Testing Strategy](docs/TESTING.md) - How to write and run deterministic tests for multi-agent logic.
+- [Skillware Integration Guide](docs/SKILLWARE.md) - Skills CLI commands, wizard assignment flow, and optional dependency behavior.
+- [Testing Strategy](docs/TESTING.md) - How to write and run deterministic tests for multi-agent and skills logic.
- [Contributing Guide](CONTRIBUTING.md) - Learn how to contribute to the project, report bugs, and follow our design philosophy.
- [Project Changelog](CHANGELOG.md) - Track all notable updates, fixes, and pre-release changes to the framework.
@@ -69,7 +71,7 @@ Rooms/
│ ├── config.py # Pydantic Configuration Models
│ ├── agent.py # Agent & LiteLLM/Custom Logic
│ ├── session.py # Turn Orchestration & Memory
-│ ├── settings.py # YAML settings loader (#26, #27)
+│ ├── settings.py # YAML settings loader
│ └── storage.py # Secure Log Serialization
├── tests/ # Unit Tests
│ └── test_session.py # Logic Verification
@@ -99,7 +101,7 @@ venv\Scripts\activate # Windows: venv\Scripts\activate | Unix: source venv/bin/
pip install -r requirements.txt
```
#### Optional: Long-Term Memory & RAG Support
-If you plan to use vector memory features (such as long-term agent memory across sessions (#13)), you will need to install the heavier machine learning dependencies separately:
+If you plan to use vector memory features, install the heavier machine learning dependencies separately:
```bash
pip install -r requirements-memory.txt
```
@@ -131,10 +133,13 @@ The wizard will step you through:
- Setting your user profile (name and background)
- Defining the session topic and turn limits
- Inviting default or custom agents with individual temperatures and system prompts
+- Optionally assigning Skillware skills (and per-skill overrides) to custom agents
- Optionally assigning a Global Orchestrator
During a session, type `@AgentName` in any user input to force a specific agent to respond next.
+For skills-specific commands and usage, see `docs/SKILLWARE.md`.
+
**Run Tests**
```bash
# Always run via pytest with PYTHONPATH set:
@@ -145,10 +150,6 @@ $env:PYTHONPATH="."; python -m pytest tests/ -v
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
-## Roadmap & Progress
-
-Track our active progress on the [GitHub Issues](https://github.com/arpahls/Rooms/issues) board.
-
diff --git a/cli.py b/cli.py
index e6f6b1c..602ce2b 100644
--- a/cli.py
+++ b/cli.py
@@ -13,6 +13,7 @@
from rooms.agent import Agent
from rooms.session import Session
from rooms.storage import save_transcript
+from rooms.skills_cli import list_skills, inspect_skill, suggest_skills
from rooms.settings import (
RoomsSettings,
SettingsError,
@@ -92,9 +93,52 @@ def create_custom_agent_wizard(settings: RoomsSettings, tracked_env_keys: Option
config.color = Prompt.ask("CLI output color (e.g. red, green, blue, cyan, magenta, yellow)", default="blue")
config.temperature = float(Prompt.ask("Generation Temperature", default=str(defaults.temperature)))
+ _assign_skills_in_wizard(config)
return config
+def _assign_skills_in_wizard(config: AgentConfig) -> None:
+ """Optional skill assignment step for custom agents."""
+ if not Confirm.ask("Assign Skillware skills to this agent?", default=False):
+ return
+
+ skills, err = list_skills()
+ if err:
+ console.print(f"[yellow]{err}[/yellow]")
+ if not Confirm.ask("Continue with manual skill IDs anyway?", default=False):
+ return
+
+ if skills:
+ console.print("\n[bold green]Available Skills[/bold green]")
+ for item in skills:
+ desc = item.get("description", "").strip()
+ suffix = f" - {desc}" if desc else ""
+ console.print(f"- {item['id']}{suffix}")
+
+ raw = Prompt.ask(
+ "Skill IDs to assign (comma separated, leave blank to skip)",
+ default="",
+ ).strip()
+ if not raw:
+ return
+ config.skills = [item.strip() for item in raw.split(",") if item.strip()]
+
+ for skill_id in config.skills:
+ if Confirm.ask(f"Add runtime config overrides for {skill_id}?", default=False):
+ cfg_raw = Prompt.ask(
+ f"Enter {skill_id} overrides as key=value pairs (comma separated)",
+ default="",
+ ).strip()
+ overrides = {}
+ if cfg_raw:
+ for pair in [p.strip() for p in cfg_raw.split(",") if p.strip()]:
+ if "=" in pair:
+ key, value = pair.split("=", 1)
+ overrides[key.strip()] = value.strip()
+ if overrides:
+ config.skill_settings[skill_id] = overrides
+
+
def main_menu(settings: RoomsSettings):
console.print(Panel.fit("[bold magenta]Multi-Agent Room Framework[/bold magenta]", subtitle="Advanced Scenario Wizard"))
default_personas = get_default_personas(settings)
@@ -286,6 +330,65 @@ def cmd_config_reset(args: argparse.Namespace) -> int:
return 0
+def cmd_skills_list(_args: argparse.Namespace) -> int:
+ skills, err = list_skills()
+ if err:
+ console.print(f"[yellow]{err}[/yellow]")
+ return 0
+ if not skills:
+ console.print("[yellow]No skills discovered.[/yellow]")
+ return 0
+
+ console.print("[bold green]Available Skills[/bold green]")
+ for item in skills:
+ desc = item.get("description", "").strip()
+ suffix = f" - {desc}" if desc else ""
+ console.print(f"- {item['id']}{suffix}")
+ return 0
+
+
+def cmd_skills_inspect(args: argparse.Namespace) -> int:
+ payload, err = inspect_skill(args.skill_id)
+ if err:
+ console.print(f"[yellow]{err}[/yellow]")
+ return 1
+
+ console.print(Panel.fit(f"[bold]{payload['id']}[/bold]", title="Skill"))
+ if payload.get("version"):
+ console.print(f"[cyan]Version:[/cyan] {payload['version']}")
+ if payload.get("description"):
+ console.print(f"[cyan]Description:[/cyan] {payload['description']}")
+ if payload.get("inputs"):
+ console.print(f"[cyan]Inputs:[/cyan] {payload['inputs']}")
+ if payload.get("instructions"):
+ console.print(Rule("Skill Instructions"))
+ console.print(payload["instructions"])
+ return 0
+
+
+def cmd_skills_suggest(args: argparse.Namespace) -> int:
+ expertise = [item.strip() for item in args.expertise.split(",") if item.strip()]
+ if not expertise:
+ console.print("[yellow]No expertise keywords provided.[/yellow]")
+ return 1
+ skills, err = list_skills()
+ if err:
+ console.print(f"[yellow]{err}[/yellow]")
+ return 0
+
+ suggested = suggest_skills(skills, expertise)
+ if not suggested:
+ console.print("[yellow]No suggested skills matched your expertise keywords.[/yellow]")
+ return 0
+
+ console.print("[bold green]Suggested Skills[/bold green]")
+ for item in suggested:
+ desc = item.get("description", "").strip()
+ suffix = f" - {desc}" if desc else ""
+ console.print(f"- {item['id']}{suffix}")
+ return 0
+
+
def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description="Multi-Agent Room Framework")
parser.add_argument(
@@ -303,6 +406,18 @@ def build_parser() -> argparse.ArgumentParser:
reset_p.add_argument("--path", help="Specific settings file to remove")
reset_p.add_argument("-y", "--yes", action="store_true", help="Skip confirmation")
+ skills_parser = sub.add_parser("skills", help="Rooms-native Skillware discovery and inspection")
+ skills_sub = skills_parser.add_subparsers(dest="skills_cmd", required=True)
+ skills_sub.add_parser("list", help="List available skills")
+ inspect_p = skills_sub.add_parser("inspect", help="Inspect a specific skill")
+ inspect_p.add_argument("skill_id", help="Skill ID, e.g. finance/wallet_screening")
+ suggest_p = skills_sub.add_parser("suggest", help="Suggest skills from expertise keywords")
+ suggest_p.add_argument(
+ "--expertise",
+ required=True,
+ help="Comma-separated keywords, e.g. finance,risk,compliance",
+ )
+
parser.add_argument(
"--skip-preflight",
action="store_true",
@@ -330,6 +445,14 @@ def main(argv: Optional[List[str]] = None) -> int:
if args.config_cmd == "reset":
return cmd_config_reset(args)
return 1
+ if args.command == "skills":
+ if args.skills_cmd == "list":
+ return cmd_skills_list(args)
+ if args.skills_cmd == "inspect":
+ return cmd_skills_inspect(args)
+ if args.skills_cmd == "suggest":
+ return cmd_skills_suggest(args)
+ return 1
try:
settings = load_settings(args.config, required=bool(args.config))
diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md
index 4d98492..7a74640 100644
--- a/docs/ARCHITECTURE.md
+++ b/docs/ARCHITECTURE.md
@@ -38,6 +38,8 @@ At the end of a session, the user is prompted to optionally save. Two formats ar
The filename is auto-suggested from a short slug of the session topic (e.g. `bioethics_of_designer_babies.md`). System bootstrap messages are excluded from saved output.
+For skill-enabled agents, transcript exports also include structured skill execution events (`role: skill`) with tool name, arguments, status, and result payload for auditability.
+
## User Profile & Participant Identity
The wizard captures a **user name and background** before the session starts. This is injected into the global session introduction, so all agents are explicitly informed of who the human participant is and can treat them as an equal voice in the room.
@@ -99,6 +101,19 @@ If you do not want to use LiteLLM at all, the framework allows you to inject any
The framework will dynamically import your file at runtime and use it exclusively for that agent's turns. Note that custom functions are executed with a timeout boundary (using the agent's configured `timeout` setting) to prevent infinite UI hangups.
+## Skillware Integration
+
+Rooms includes optional Skillware support through native CLI and wizard flows.
+
+The integration is designed to:
+
+- preserve Rooms terminal UX and styling
+- fail gracefully when Skillware is unavailable
+- keep skill loading lazy and per-agent
+- keep user-facing answers natural while logging structured tool events
+
+For command usage and setup, see `docs/SKILLWARE.md`.
+
## CI/CD and Robustness
To ensure the framework remains stable as it grows, we maintain a comprehensive CI/CD pipeline using **GitHub Actions**. Every contribution is automatically tested against Python 3.13 for:
- **Linting**: High-standard code hygiene via `flake8`.
diff --git a/docs/EXAMPLES.md b/docs/EXAMPLES.md
index a90d483..1de0135 100644
--- a/docs/EXAMPLES.md
+++ b/docs/EXAMPLES.md
@@ -230,3 +230,15 @@ If you are running the application in a CI/CD automation environment, running au
```bash
python cli.py --skip-preflight
```
+
+### Skills in Real Sessions
+
+You can assign optional skills to custom agents during wizard setup.
+
+Recommended flow:
+
+- start with one focused skill per agent
+- keep expertise keywords aligned with expected tool usage
+- use per-skill overrides only when needed
+
+For complete command reference and setup, see `docs/SKILLWARE.md`.
diff --git a/docs/SKILLWARE.md b/docs/SKILLWARE.md
new file mode 100644
index 0000000..d5b1471
--- /dev/null
+++ b/docs/SKILLWARE.md
@@ -0,0 +1,58 @@
+# Skillware Integration
+
+Rooms supports optional Skillware-based tool use for agents.
+
+## Design Principles
+
+- Skills are assigned per agent, not globally.
+- Skillware is loaded lazily only when an agent has configured skills.
+- Agent replies remain human-readable even when tools are used.
+- Skill execution metadata is logged as structured session events.
+
+## Install (Optional)
+
+```bash
+pip install skillware
+```
+
+Rooms works normally without Skillware. Skill commands and wizard steps fail gracefully with guidance.
+
+## Skills CLI Commands
+
+```bash
+python cli.py skills list
+python cli.py skills inspect finance/wallet_screening
+python cli.py skills suggest --expertise finance,risk,compliance
+```
+
+## Wizard Assignment Flow
+
+When creating a custom agent, you can optionally:
+
+- assign one or more skill IDs
+- add per-skill override settings (`key=value` pairs)
+- skip skills entirely
+
+Assigned skills are stored in agent config:
+
+- `skills`
+- `skill_settings`
+
+## Runtime Behavior
+
+- Tools are exposed to the model only for agents with configured skills.
+- Skill calls are guarded by per-turn and per-session limits.
+- Tool results are passed back to the model for second-pass synthesis.
+- Final user-visible output remains a normal agent message, not raw JSON.
+
+## Session Logging and Transcripts
+
+Skill calls are recorded as structured `role: skill` events in session history.
+
+Saved transcripts include those events with:
+
+- agent name
+- tool name
+- arguments
+- status
+- result payload
diff --git a/docs/TESTING.md b/docs/TESTING.md
index 3fb7ed8..6e52141 100644
--- a/docs/TESTING.md
+++ b/docs/TESTING.md
@@ -25,7 +25,7 @@ PYTHONPATH=. python -m pytest tests/ -v
## Settings / CLI smoke (no Ollama)
-Fast checks for [#26](https://github.com/ARPAHLS/rooms/issues/26) / [#27](https://github.com/ARPAHLS/rooms/issues/27) — no interactive wizard, no live inference:
+Fast checks for settings and CLI behavior with no interactive wizard and no live inference:
```bash
# Windows (PowerShell)
@@ -36,7 +36,8 @@ $env:PYTHONPATH="."; python -m pytest tests/test_settings.py tests/test_cli_sett
|---|---|
| `tests/test_settings.py` | YAML load/validation, personas, builtin defaults; asserts `rooms.settings.example.yaml` exists in repo |
| `tests/test_cli_settings_smoke.py` | `cli.py config init`, `config reset`, `--config` wiring |
-| `tests/test_cli.py` | Wizard API-key env cleanup (#5) |
+| `tests/test_cli.py` | Wizard env cleanup, Skills CLI command behavior, wizard skill assignment flow |
+| `tests/test_skills_cli.py` | Skillware wrapper discovery/inspect normalization and suggestion matching |
## Session logic coverage
@@ -57,6 +58,15 @@ $env:PYTHONPATH="."; python -m pytest tests/test_settings.py tests/test_cli_sett
Run the full suite with `python -m pytest tests/ -v` (see **Running Tests** above).
+## Skillware UX coverage
+
+Rooms includes tests for native Skillware UX:
+
+- `skills list` command output path (and graceful no-Skillware path)
+- `skills inspect