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
32 changes: 32 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: CI

on:
pull_request:
push:
branches:
- main

jobs:
test:
name: Swift Test
runs-on: macos-15
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Show toolchain
run: swift --version

- name: Ensure Swift 6+
run: |
SWIFT_MAJOR="$(swift --version | awk '/Swift version/ { split($3, v, "."); print v[1] }')"
if [ "${SWIFT_MAJOR}" -lt 6 ]; then
echo "Swift 6+ is required by Package.swift (swift-tools-version: 6.0)."
exit 1
fi

- name: Run full test suite
run: swift test

- name: Run run+agent E2E test only
run: swift test --filter ScriptoriaCoreTests.ScriptoriaCLITests/testRunCommandAgentStage
238 changes: 238 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
# Scriptoria

Scriptoria is a macOS automation script manager — a menu bar app + CLI tool for organizing, running, and scheduling shell scripts.

## Architecture

- **ScriptoriaApp** — SwiftUI macOS app (menu bar + main window)
- **ScriptoriaCLI** — Command-line tool (`scriptoria`)
- **ScriptoriaCore** — Shared library (models, storage, execution)
- Storage: SQLite via GRDB at `~/.scriptoria/` (configurable)
- Scheduling: macOS launchd agents

## Build & Run

```bash
swift build # Build all targets
swift run scriptoria --help # Run CLI
swift test # Run tests
```

## CLI Installation

The CLI binary is at `.build/debug/scriptoria` after building. To install system-wide:

```bash
# Option 1: Symlink (recommended for development)
sudo ln -sf "$(pwd)/.build/debug/scriptoria" /usr/local/bin/scriptoria

# Option 2: Via the GUI app
# Settings > General > Shell Command > Install
```

## CLI Reference

### `scriptoria add <path>` — Add a script

```bash
scriptoria add ./backup.sh
scriptoria add ~/scripts/deploy.sh --title "Deploy" --description "Deploy to prod" --interpreter bash --tags "deploy,prod"
```

Options:
- `-t, --title` — Display name (defaults to filename)
- `-d, --description` — Description text
- `-i, --interpreter` — One of: `auto`, `bash`, `zsh`, `sh`, `node`, `python3`, `ruby`, `osascript`, `binary`
- `--tags` — Comma-separated tags (e.g. `"backup,daily"`)

### `scriptoria list` — List scripts

```bash
scriptoria list # All scripts
scriptoria list --tag backup # Filter by tag
scriptoria list --favorites # Only favorites
scriptoria list --recent # Recently run
```

Output shows: status icon, title, ID prefix, interpreter, tags, run count.

### `scriptoria run <title-or-id>` — Run a script

```bash
scriptoria run "Deploy" # By title
scriptoria run 3A1F2B4C-... # By full UUID
scriptoria run deploy --notify # Send macOS notification on finish
scriptoria run deploy --scheduled # Scheduled mode (auto-notify, less output)
scriptoria run --id "3A1F2B4C-..." # Explicit --id flag
```

Exit code matches the script's exit code. Run history is saved to the database.

### `scriptoria search <query>` — Search scripts

```bash
scriptoria search backup # Search title, description, tags
```

### `scriptoria remove <title-or-id>` — Remove a script

```bash
scriptoria remove "Deploy"
scriptoria remove 3A1F2B4C
```

### `scriptoria tags` — List all tags

```bash
scriptoria tags # Shows all tags with script counts
```

### `scriptoria schedule` — Manage scheduled tasks

#### List schedules

```bash
scriptoria schedule list # Shows all schedules with status, next run time
scriptoria schedule # Same (list is default)
```

#### Add a schedule

```bash
# Run every 30 minutes
scriptoria schedule add "Backup" --every 30

# Run daily at 09:00
scriptoria schedule add "Report" --daily 09:00

# Run on specific weekdays at a time
scriptoria schedule add "Deploy" --weekly "mon,wed,fri@09:00"
```

Schedule types:
- `--every <minutes>` — Interval-based (e.g. every 30 minutes)
- `--daily HH:MM` — Daily at a specific time
- `--weekly "days@HH:MM"` — Weekly on specific days. Days: `sun`, `mon`, `tue`, `wed`, `thu`, `fri`, `sat`

Schedules are backed by macOS launchd agents and persist across reboots.

#### Enable / Disable / Remove a schedule

```bash
scriptoria schedule enable <schedule-id> # ID prefix works (e.g. "3A1F2B4C")
scriptoria schedule disable <schedule-id>
scriptoria schedule remove <schedule-id>
```

### `scriptoria config` — Configuration

```bash
scriptoria config show # Show current config
scriptoria config set-dir ~/my-data # Set data directory
```

## Typical AI Workflow

A complete example of adding a script, scheduling it, and verifying:

```bash
# 1. Write a script
cat > /tmp/health-check.sh << 'EOF'
#!/bin/bash
curl -sf https://example.com/health && echo "OK" || echo "FAIL"
EOF
chmod +x /tmp/health-check.sh

# 2. Add to Scriptoria
scriptoria add /tmp/health-check.sh --title "Health Check" --description "Check service health" --tags "monitoring,health"

# 3. Test run
scriptoria run "Health Check"

# 4. Schedule every 10 minutes
scriptoria schedule add "Health Check" --every 10

# 5. Verify
scriptoria list
scriptoria schedule list
```

## Key File Paths

- CLI entry: `Sources/ScriptoriaCLI/CLI.swift`
- Commands: `Sources/ScriptoriaCLI/Commands/`
- Models: `Sources/ScriptoriaCore/Models/` (Script, ScriptRun, Schedule)
- Storage: `Sources/ScriptoriaCore/Storage/` (ScriptStore, DatabaseManager, Config)
- Execution: `Sources/ScriptoriaCore/Execution/ScriptRunner.swift`
- Scheduling: `Sources/ScriptoriaCore/Scheduling/` (ScheduleStore, LaunchdHelper)
- App views: `Sources/ScriptoriaApp/Views/`
- App state: `Sources/ScriptoriaApp/AppState.swift`
- Theme: `Sources/ScriptoriaApp/Styles/Theme.swift`

## Local Coding Agent Integration (Claude/Codex/Kimi)

Scriptoria's post-script agent stage should be able to run a local coding agent provider:

- `codex` (native)
- `claude` (via local adapter)
- `kimi` (via local adapter)

### Unified transport contract

Use a single stdio JSON-RPC contract for all providers (native or adapter):

- Request methods:
- `initialize`
- `thread/start`
- `turn/start`
- `turn/steer`
- `turn/interrupt`
- Notifications/events:
- `thread/started`
- `turn/started`
- `item/agentMessage/delta`
- `item/commandExecution/outputDelta`
- `item/completed`
- `turn/completed`

### Execution rule

- Keep `PostScriptAgentRunner` provider-agnostic.
- Select provider by executable path, not by hard-coded branches in core logic.
- Current runtime switch is `SCRIPTORIA_CODEX_EXECUTABLE` (or launch option executable).
- For `claude` and `kimi`, point this executable to a local adapter that exposes the same app-server protocol.

### Adapter requirements (for Claude/Kimi)

- Must accept `app-server --listen stdio://`.
- Must read newline-delimited JSON-RPC messages from stdin.
- Must write newline-delimited JSON-RPC messages to stdout.
- Must preserve streaming behavior (`delta` events).
- Must support `turn/steer` and `turn/interrupt`.
- Must exit non-zero on unrecoverable startup/runtime errors.

### Example usage

```bash
# Codex native
SCRIPTORIA_CODEX_EXECUTABLE="$(which codex)" \
scriptoria run "My Task" --model gpt-5.3-codex --no-steer

# Claude via local adapter
SCRIPTORIA_CODEX_EXECUTABLE="$HOME/.scriptoria/agents/claude-adapter" \
scriptoria run "My Task" --model claude-sonnet --no-steer

# Kimi via local adapter
SCRIPTORIA_CODEX_EXECUTABLE="$HOME/.scriptoria/agents/kimi-adapter" \
scriptoria run "My Task" --model kimi-k2 --no-steer
```

### Testing expectations

- Validate one end-to-end run per provider (codex/claude/kimi adapter).
- Validate streaming output is visible in CLI during agent run.
- Validate steer/interrupt commands are accepted while the same session is running.
- Validate task memory is written after completion:
- `task-name/task/YYYYMMDDHHMMSS.md`
- Validate workspace memory summarize command still works:
- `task-name/workspace.md`
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ let package = Package(
// Tests
.testTarget(
name: "ScriptoriaCoreTests",
dependencies: ["ScriptoriaCore"],
dependencies: ["ScriptoriaCore", "ScriptoriaCLI"],
path: "Tests/ScriptoriaCoreTests"
),
]
Expand Down
64 changes: 45 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ Built with Swift, SwiftUI, SQLite ([GRDB](https://github.com/groue/GRDB.swift)),
A full-featured command-line tool for terminal workflows and automation:

```bash
scriptoria add ./backup.sh --title "Backup" --tags "daily,infra"
scriptoria add ./backup.sh --title "Backup" --task-name "Daily Backup" --default-model gpt-5.3-codex --tags "daily,infra"
scriptoria list --tag daily
scriptoria run "Backup" --notify
scriptoria run "Backup" --model gpt-5.3-codex --no-steer
scriptoria schedule add "Backup" --daily 09:00
scriptoria search "deploy"
scriptoria tags
Expand All @@ -32,9 +32,9 @@ scriptoria config show

| Command | Description |
|---------|-------------|
| `add <path>` | Register a script (with title, description, interpreter, tags) |
| `add <path>` | Register a script (title/description/interpreter/tags/agent task/model defaults) |
| `list` | List scripts (filter by `--tag`, `--favorites`, `--recent`) |
| `run <title-or-id>` | Execute a script, save run history |
| `run <title-or-id>` | Execute a script, optional post-script agent stage (`--model`, `--agent-prompt`, `--command`, `--skip-agent`) |
| `search <query>` | Search by title, description, or tags |
| `remove <title-or-id>` | Remove a script from the database |
| `tags` | List all tags with script counts |
Expand All @@ -46,36 +46,62 @@ scriptoria config show

### AI Agent Friendly

Scriptoria is designed to work seamlessly with AI coding agents like [Claude Code](https://claude.ai/claude-code).
Scriptoria includes a reusable [skill](skills/scriptoria/SKILL.md) and a provider-agnostic agent runtime, so coding agents can manage scripts end to end.

**Claude Code Skill** — The project includes a [skill](skills/scriptoria/SKILL.md) that teaches Claude Code how to use Scriptoria. When the skill is active, Claude can:
#### Install the Scriptoria Skill (Codex)

- Write shell scripts and register them with `scriptoria add`
- Run scripts and inspect output via `scriptoria run`
- Set up automated schedules with `scriptoria schedule add`
- Search and manage your script library
```bash
# Install from local repo (recommended during development)
mkdir -p ~/.codex/skills/scriptoria
ln -sfn "$(pwd)/skills/scriptoria/SKILL.md" ~/.codex/skills/scriptoria/SKILL.md

# Or install from a GitHub repo path
python3 ~/.codex/skills/.system/skill-installer/scripts/install-skill-from-github.py \
--repo <owner>/<repo> \
--path skills/scriptoria \
--ref main
```

After installation, restart Codex so the new skill is loaded.

#### Best-fit Tasks for This Skill

- Create/register scripts: `scriptoria add ...`
- Run scripts and inspect output/errors: `scriptoria run ...`, `scriptoria logs ...`
- Configure recurring jobs: `scriptoria schedule add|list|enable|disable|remove ...`
- Search, classify, and clean up script inventory: `scriptoria search|tags|remove ...`
- Memory-oriented post-script workflows (task/workspace summaries): `scriptoria memory ...`

This skill should prefer Scriptoria CLI scheduling commands over direct `launchd` or `cron` edits.

#### Supported Coding Agents

- **Codex (native)**: direct support via `codex app-server`
- **Claude (adapter mode)**: supported through a local adapter that exposes the same app-server JSON-RPC protocol
- **Kimi (adapter mode)**: supported through a local adapter with the same contract

Runtime provider selection is done by executable path (`SCRIPTORIA_CODEX_EXECUTABLE`), keeping `ScriptoriaCore` provider-agnostic.

Example agent workflow:

```bash
# Claude can do this entire flow autonomously:
cat > /tmp/health-check.sh << 'EOF'
#!/bin/bash
curl -sf https://example.com/health && echo "OK" || echo "FAIL"
EOF
chmod +x /tmp/health-check.sh

scriptoria add /tmp/health-check.sh --title "Health Check" --tags "monitoring"
scriptoria run "Health Check"
scriptoria run "Health Check" --model gpt-5.3-codex --no-steer
scriptoria schedule add "Health Check" --every 10
```

**Why it works well with agents:**
Why it works well with agents:

- All CLI commands are non-interactive — no prompts, no TTY required
- Structured output with clear success/error indicators
- UUID-based script references for unambiguous identification
- Full CRUD via CLI — agents never need the GUI
- Chainable commands for end-to-end automation in a single flow
- CLI flows are automation-friendly and mostly non-interactive
- Structured status and stored run history simplify agent follow-up
- UUID-based references reduce ambiguity
- Full lifecycle coverage is available from CLI (create, run, schedule, inspect, clean up)

## Architecture

Expand All @@ -86,7 +112,7 @@ Scriptoria/
│ ├── ScriptoriaCLI/ # CLI tool (swift-argument-parser)
│ └── ScriptoriaCore/ # Shared library (models, storage, execution, scheduling)
├── Tests/
├── skills/scriptoria/ # Claude Code skill definition
├── skills/scriptoria/ # Scriptoria skill definition
├── CLAUDE.md # AI agent project context
└── Package.swift
```
Expand Down
Loading