Update description
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# Pyra
|
||||
|
||||
A personal AI assistant CLI with vault-first security. Combines multi-provider AI chat with
|
||||
long-term memory and (coming) automation skills.
|
||||
A personal AI assistant CLI with vault-first security. Combines multi-provider AI chat,
|
||||
long-term memory, and an extensible plugin system.
|
||||
|
||||
## Quick Start
|
||||
|
||||
@@ -31,6 +31,11 @@ pyra chat # start talking
|
||||
| `pyra memory read <name>` | Read a memory file |
|
||||
| `pyra memory write <name> <content>` | Write 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
|
||||
|
||||
@@ -38,6 +43,7 @@ pyra chat # start talking
|
||||
|---------|-------------|
|
||||
| `/help` | Show available commands |
|
||||
| `/memory list` | List memory files |
|
||||
| `/config` | Open the configuration TUI |
|
||||
| `/clear` | Clear conversation history |
|
||||
| `/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`
|
||||
- **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
|
||||
|
||||
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/
|
||||
├── user/profile.md ← who you are
|
||||
├── context/ ← ongoing projects
|
||||
└── knowledge/ ← general notes
|
||||
├── knowledge/ ← general notes
|
||||
└── memory.db ← FTS5 search index (auto-managed)
|
||||
```
|
||||
|
||||
## `~/.pyra/` Directory
|
||||
@@ -67,15 +90,25 @@ Files are plain Markdown stored in `~/.pyra/memory/`:
|
||||
├── config.yaml ← provider + model (no secrets)
|
||||
├── security.log ← injection event log
|
||||
├── 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
|
||||
└── secrets/api_keys.json
|
||||
```
|
||||
|
||||
## Roadmap
|
||||
|
||||
- **Stage 1** (now): Core CLI, multi-provider chat, memory, vault security
|
||||
- **Stage 2**: Skills — shell/PowerShell/Python automations with user approval gates
|
||||
- **Stage 3**: Vault encryption with `age`
|
||||
- **Stage 4**: Security audit sub-agent
|
||||
- **Stage 5**: Web UI, embedding-based memory search
|
||||
- **Stage 1** ✅ Core CLI — multi-provider chat, memory, vault security
|
||||
- **Stage 2** ✅ Plugin Framework — extensible tools, slash commands, approval gates
|
||||
- **Stage 3** ✅ Memory Database — SQLite + FTS5 full-text search index
|
||||
- **Stage 4** Vault Encryption — `age`-based encryption of `~/.pyra/vault/secrets/`
|
||||
- **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)
|
||||
console.print(f"[green]Installed:[/green] {name}")
|
||||
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:
|
||||
console.print(f"[red]Error:[/red] {exc}")
|
||||
except Exception as exc:
|
||||
@@ -269,40 +269,40 @@ def daemon() -> None:
|
||||
@daemon.command("start")
|
||||
def daemon_start() -> None:
|
||||
"""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")
|
||||
def daemon_stop() -> None:
|
||||
"""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")
|
||||
def daemon_status() -> None:
|
||||
"""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")
|
||||
def daemon_restart() -> None:
|
||||
"""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")
|
||||
def daemon_install() -> None:
|
||||
"""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")
|
||||
def daemon_uninstall() -> None:
|
||||
"""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)
|
||||
def daemon_run() -> None:
|
||||
"""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