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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,8 @@ uv run octopal skill list
uv run octopal skill install <publisher>/<skill-pack>
uv run octopal skill update <skill-id>
uv run octopal skill verify <skill-id>
uv run octopal skill disable <skill-id>
uv run octopal skill enable <skill-id>
uv run octopal skill trust <skill-id>
uv run octopal skill remove <skill-id>
```
Expand Down
4 changes: 4 additions & 0 deletions docs/skills.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ uv run octopal skill install <source>
uv run octopal skill list
uv run octopal skill update <skill-id>
uv run octopal skill verify <skill-id>
uv run octopal skill disable <skill-id>
uv run octopal skill enable <skill-id>
uv run octopal skill trust <skill-id>
uv run octopal skill untrust <skill-id>
uv run octopal skill remove <skill-id>
Expand Down Expand Up @@ -275,6 +277,8 @@ Current requirement checks:
- missing config keys from `requires.config`
- untrusted imported script bundles

Use `octopal skill disable <skill-id>` to keep an installed bundle on disk while removing it from active skill use. Re-enable it with `octopal skill enable <skill-id>`.

Config requirements are currently checked via env vars named like:

```text
Expand Down
61 changes: 60 additions & 1 deletion src/octopal/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,12 @@
update_installed_skill,
verify_installed_skill,
)
from octopal.tools.skills.management import list_skill_inventory, remove_skill, set_skill_trust
from octopal.tools.skills.management import (
list_skill_inventory,
remove_skill,
set_skill_enabled,
set_skill_trust,
)
from octopal.tools.skills.runtime_envs import (
prepare_skill_env,
remove_skill_env,
Expand Down Expand Up @@ -2158,6 +2163,60 @@ def skill_trust(
console.print(f"[bold green][V] Trusted skill[/bold green] {payload['skill_id']}")


@skill_app.command("enable")
def skill_enable(
skill_id: str = typer.Argument(..., help="Skill id."),
json_output: bool = typer.Option(False, "--json", help="Print machine-readable JSON."),
) -> None:
"""Enable a skill without reinstalling it."""
settings = load_settings()
try:
payload = set_skill_enabled(
skill_id,
workspace_dir=settings.workspace_dir.resolve(),
enabled=True,
)
except Exception as exc:
if json_output:
typer.echo(json.dumps({"status": "error", "message": str(exc), "skill_id": skill_id}, ensure_ascii=False))
else:
console.print(f"[bold red]Skill enable failed:[/bold red] {exc}")
raise typer.Exit(code=1) from None

if json_output:
typer.echo(json.dumps(payload, ensure_ascii=False, indent=2))
return

console.print(f"[bold green][V] Enabled skill[/bold green] {payload['skill_id']}")


@skill_app.command("disable")
def skill_disable(
skill_id: str = typer.Argument(..., help="Skill id."),
json_output: bool = typer.Option(False, "--json", help="Print machine-readable JSON."),
) -> None:
"""Disable a skill without deleting its bundle."""
settings = load_settings()
try:
payload = set_skill_enabled(
skill_id,
workspace_dir=settings.workspace_dir.resolve(),
enabled=False,
)
except Exception as exc:
if json_output:
typer.echo(json.dumps({"status": "error", "message": str(exc), "skill_id": skill_id}, ensure_ascii=False))
else:
console.print(f"[bold red]Skill disable failed:[/bold red] {exc}")
raise typer.Exit(code=1) from None

if json_output:
typer.echo(json.dumps(payload, ensure_ascii=False, indent=2))
return

console.print(f"[bold green][V] Disabled skill[/bold green] {payload['skill_id']}")


@skill_app.command("verify")
def skill_verify(
skill_id: str = typer.Argument(..., help="Installer-managed skill id."),
Expand Down
Loading