Update description
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
# Pyra
|
# Pyra
|
||||||
|
|
||||||
A personal AI assistant CLI with vault-first security. Combines multi-provider AI chat with
|
A personal AI assistant CLI with vault-first security. Combines multi-provider AI chat,
|
||||||
long-term memory and (coming) automation skills.
|
long-term memory, and an extensible plugin system.
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
@@ -31,6 +31,11 @@ pyra chat # start talking
|
|||||||
| `pyra memory read <name>` | Read a memory file |
|
| `pyra memory read <name>` | Read a memory file |
|
||||||
| `pyra memory write <name> <content>` | Write a memory file |
|
| `pyra memory write <name> <content>` | Write a memory file |
|
||||||
| `pyra memory append <name> <content>` | Append to a memory file |
|
| `pyra memory append <name> <content>` | Append to a memory file |
|
||||||
|
| `pyra plugin list` | List installed and available plugins |
|
||||||
|
| `pyra plugin install <name>` | Install a bundled plugin |
|
||||||
|
| `pyra plugin enable <name>` | Enable an installed plugin |
|
||||||
|
| `pyra plugin disable <name>` | Disable a plugin (keeps it installed) |
|
||||||
|
| `pyra plugin setup <name>` | Run a plugin's credential setup wizard |
|
||||||
|
|
||||||
### In-chat slash commands
|
### In-chat slash commands
|
||||||
|
|
||||||
@@ -38,6 +43,7 @@ pyra chat # start talking
|
|||||||
|---------|-------------|
|
|---------|-------------|
|
||||||
| `/help` | Show available commands |
|
| `/help` | Show available commands |
|
||||||
| `/memory list` | List memory files |
|
| `/memory list` | List memory files |
|
||||||
|
| `/config` | Open the configuration TUI |
|
||||||
| `/clear` | Clear conversation history |
|
| `/clear` | Clear conversation history |
|
||||||
| `/quit` or `/exit` | Exit Pyra |
|
| `/quit` or `/exit` | Exit Pyra |
|
||||||
|
|
||||||
@@ -48,16 +54,33 @@ pyra chat # start talking
|
|||||||
- **Prompt injection scanner** — warns on suspicious AI output, logs to `~/.pyra/security.log`
|
- **Prompt injection scanner** — warns on suspicious AI output, logs to `~/.pyra/security.log`
|
||||||
- **Path sandboxing** — the AI can only reference memory files by name; traversal is blocked
|
- **Path sandboxing** — the AI can only reference memory files by name; traversal is blocked
|
||||||
|
|
||||||
|
## Plugins
|
||||||
|
|
||||||
|
Pyra has an extensible plugin system. Bundled plugins are shipped with Pyra and installed on
|
||||||
|
demand; third-party plugins can be dropped into `~/.pyra/plugins/` directly.
|
||||||
|
|
||||||
|
Each plugin is a directory containing a `manifest.json` and a `plugin.py`. Plugin credentials
|
||||||
|
are stored in the vault under namespaced keys (`plugin:<name>:<key>`) — never in `config.yaml`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pyra plugin list # see what's available
|
||||||
|
pyra plugin install <name> # copy a bundled plugin to ~/.pyra/plugins/
|
||||||
|
pyra plugin setup <name> # enter credentials (stored in vault)
|
||||||
|
pyra plugin enable <name> # activate for the next chat session
|
||||||
|
```
|
||||||
|
|
||||||
## Memory
|
## Memory
|
||||||
|
|
||||||
Pyra reads your memory files at the start of each session and injects them as context.
|
Pyra reads your memory files at the start of each session and injects them as context.
|
||||||
Files are plain Markdown stored in `~/.pyra/memory/`:
|
Files are plain Markdown stored in `~/.pyra/memory/`, indexed by a SQLite full-text search
|
||||||
|
database (`memory.db`) for fast in-chat lookup.
|
||||||
|
|
||||||
```
|
```
|
||||||
~/.pyra/memory/
|
~/.pyra/memory/
|
||||||
├── user/profile.md ← who you are
|
├── user/profile.md ← who you are
|
||||||
├── context/ ← ongoing projects
|
├── context/ ← ongoing projects
|
||||||
└── knowledge/ ← general notes
|
├── knowledge/ ← general notes
|
||||||
|
└── memory.db ← FTS5 search index (auto-managed)
|
||||||
```
|
```
|
||||||
|
|
||||||
## `~/.pyra/` Directory
|
## `~/.pyra/` Directory
|
||||||
@@ -67,15 +90,25 @@ Files are plain Markdown stored in `~/.pyra/memory/`:
|
|||||||
├── config.yaml ← provider + model (no secrets)
|
├── config.yaml ← provider + model (no secrets)
|
||||||
├── security.log ← injection event log
|
├── security.log ← injection event log
|
||||||
├── memory/ ← AI-readable long-term memory
|
├── memory/ ← AI-readable long-term memory
|
||||||
├── skills/ ← automation scripts (Stage 2)
|
│ └── memory.db ← SQLite FTS5 search index
|
||||||
|
├── plugins/ ← installed plugins
|
||||||
|
│ └── <name>/
|
||||||
|
│ ├── manifest.json
|
||||||
|
│ └── plugin.py
|
||||||
|
├── logs/ ← execution logs
|
||||||
|
│ ├── tool_executions.log
|
||||||
|
│ └── plugin_errors.log
|
||||||
└── vault/ ← secure, AI-inaccessible storage
|
└── vault/ ← secure, AI-inaccessible storage
|
||||||
└── secrets/api_keys.json
|
└── secrets/api_keys.json
|
||||||
```
|
```
|
||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
- **Stage 1** (now): Core CLI, multi-provider chat, memory, vault security
|
- **Stage 1** ✅ Core CLI — multi-provider chat, memory, vault security
|
||||||
- **Stage 2**: Skills — shell/PowerShell/Python automations with user approval gates
|
- **Stage 2** ✅ Plugin Framework — extensible tools, slash commands, approval gates
|
||||||
- **Stage 3**: Vault encryption with `age`
|
- **Stage 3** ✅ Memory Database — SQLite + FTS5 full-text search index
|
||||||
- **Stage 4**: Security audit sub-agent
|
- **Stage 4** Vault Encryption — `age`-based encryption of `~/.pyra/vault/secrets/`
|
||||||
- **Stage 5**: Web UI, embedding-based memory search
|
- **Stage 5** Skills System — YAML-defined multi-plugin workflows with event triggers
|
||||||
|
- **Stage 6** Daemon + Messaging Bots — always-on asyncio daemon, Matrix/Telegram/Signal bots
|
||||||
|
- **Stage 7** Security Audit Sub-agent — automated scanning for injection, CVEs, permission drift
|
||||||
|
- **Stage 8** Web UI — optional local interface, embedding-based memory search
|
||||||
|
|||||||
+8
-8
@@ -174,7 +174,7 @@ def plugin_install(name: str) -> None:
|
|||||||
install_bundled_plugin(name, bundled_dir, plugins_dir)
|
install_bundled_plugin(name, bundled_dir, plugins_dir)
|
||||||
console.print(f"[green]Installed:[/green] {name}")
|
console.print(f"[green]Installed:[/green] {name}")
|
||||||
console.print(f" Enable: [dim]pyra plugin enable {name}[/dim]")
|
console.print(f" Enable: [dim]pyra plugin enable {name}[/dim]")
|
||||||
console.print(f" Confirm: [dim]pyra plugin setup {name}[/dim]")
|
console.print(f" Configure: [dim]pyra plugin setup {name}[/dim]")
|
||||||
except FileNotFoundError as exc:
|
except FileNotFoundError as exc:
|
||||||
console.print(f"[red]Error:[/red] {exc}")
|
console.print(f"[red]Error:[/red] {exc}")
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
@@ -269,40 +269,40 @@ def daemon() -> None:
|
|||||||
@daemon.command("start")
|
@daemon.command("start")
|
||||||
def daemon_start() -> None:
|
def daemon_start() -> None:
|
||||||
"""Start the Pyra daemon in the background."""
|
"""Start the Pyra daemon in the background."""
|
||||||
console.print("[yellow]Daemon (Stage 2.4) is not yet implemented.[/yellow]")
|
console.print("[yellow]Daemon (Stage 6) is not yet implemented.[/yellow]")
|
||||||
|
|
||||||
|
|
||||||
@daemon.command("stop")
|
@daemon.command("stop")
|
||||||
def daemon_stop() -> None:
|
def daemon_stop() -> None:
|
||||||
"""Stop the running Pyra daemon."""
|
"""Stop the running Pyra daemon."""
|
||||||
console.print("[yellow]Daemon (Stage 2.4) is not yet implemented.[/yellow]")
|
console.print("[yellow]Daemon (Stage 6) is not yet implemented.[/yellow]")
|
||||||
|
|
||||||
|
|
||||||
@daemon.command("status")
|
@daemon.command("status")
|
||||||
def daemon_status() -> None:
|
def daemon_status() -> None:
|
||||||
"""Show daemon status."""
|
"""Show daemon status."""
|
||||||
console.print("[yellow]Daemon (Stage 2.4) is not yet implemented.[/yellow]")
|
console.print("[yellow]Daemon (Stage 6) is not yet implemented.[/yellow]")
|
||||||
|
|
||||||
|
|
||||||
@daemon.command("restart")
|
@daemon.command("restart")
|
||||||
def daemon_restart() -> None:
|
def daemon_restart() -> None:
|
||||||
"""Restart the Pyra daemon."""
|
"""Restart the Pyra daemon."""
|
||||||
console.print("[yellow]Daemon (Stage 2.4) is not yet implemented.[/yellow]")
|
console.print("[yellow]Daemon (Stage 6) is not yet implemented.[/yellow]")
|
||||||
|
|
||||||
|
|
||||||
@daemon.command("install")
|
@daemon.command("install")
|
||||||
def daemon_install() -> None:
|
def daemon_install() -> None:
|
||||||
"""Install Pyra as a system service (launchd/systemd)."""
|
"""Install Pyra as a system service (launchd/systemd)."""
|
||||||
console.print("[yellow]Daemon service install (Stage 2.4) is not yet implemented.[/yellow]")
|
console.print("[yellow]Daemon service install (Stage 6) is not yet implemented.[/yellow]")
|
||||||
|
|
||||||
|
|
||||||
@daemon.command("uninstall")
|
@daemon.command("uninstall")
|
||||||
def daemon_uninstall() -> None:
|
def daemon_uninstall() -> None:
|
||||||
"""Remove the Pyra system service."""
|
"""Remove the Pyra system service."""
|
||||||
console.print("[yellow]Daemon service uninstall (Stage 2.4) is not yet implemented.[/yellow]")
|
console.print("[yellow]Daemon service uninstall (Stage 6) is not yet implemented.[/yellow]")
|
||||||
|
|
||||||
|
|
||||||
@daemon.command("run", hidden=True)
|
@daemon.command("run", hidden=True)
|
||||||
def daemon_run() -> None:
|
def daemon_run() -> None:
|
||||||
"""Run daemon in foreground (used by service manager)."""
|
"""Run daemon in foreground (used by service manager)."""
|
||||||
console.print("[yellow]Daemon (Stage 2.4) is not yet implemented.[/yellow]")
|
console.print("[yellow]Daemon (Stage 6) is not yet implemented.[/yellow]")
|
||||||
|
|||||||
Reference in New Issue
Block a user