Skip to content
Open
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
14 changes: 14 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,19 @@ jobs:
- name: Run full test suite
run: swift test

- name: Verify Flow TC mapping is up to date
run: |
scripts/generate-flow-tc-mapping.sh
git diff --exit-code -- docs/flow-tc-mapping.md

- name: Verify Flow GUI TC mapping contract
run: scripts/verify-flow-gui-tc-mapping.sh

- name: Verify Flow DB migration contract
run: scripts/verify-flow-db-migrations.sh

- name: Verify Flow concurrent-run smoke
run: scripts/verify-flow-concurrent-run-smoke.sh

- name: Run run+agent E2E test only
run: swift test --filter ScriptoriaCoreTests.ScriptoriaCLITests/testRunCommandAgentStage
18 changes: 18 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,23 @@ scriptoria config show # Show current config
scriptoria config set-dir ~/my-data # Set data directory
```

### `scriptoria flow` — Flow DSL (state machine automation)

#### Validate / Compile / Run / Dry-Run

```bash
scriptoria flow validate ./flow.yaml
scriptoria flow compile ./flow.yaml --out ./flow.ir.json
scriptoria flow run ./flow.yaml --var repo=org/repo --max-agent-rounds 10 --command "/interrupt"
scriptoria flow dry-run ./flow.yaml --fixture ./fixture.json
```

Subcommands:
- `flow validate <flow.yaml> [--no-fs-check]`
- `flow compile <flow.yaml> --out <flow.json> [--no-fs-check]`
- `flow run <flow.yaml> [--var <k=v> ...] [--max-agent-rounds <n>] [--no-steer] [--command <cmd> ...]`
- `flow dry-run <flow.yaml> --fixture <fixture.json>`

## Typical AI Workflow

A complete example of adding a script, scheduling it, and verifying:
Expand Down Expand Up @@ -164,6 +181,7 @@ scriptoria schedule list
- Models: `Sources/ScriptoriaCore/Models/` (Script, ScriptRun, Schedule)
- Storage: `Sources/ScriptoriaCore/Storage/` (ScriptStore, DatabaseManager, Config)
- Execution: `Sources/ScriptoriaCore/Execution/ScriptRunner.swift`
- Flow: `Sources/ScriptoriaCore/Flow/`
- Scheduling: `Sources/ScriptoriaCore/Scheduling/` (ScheduleStore, LaunchdHelper)
- App views: `Sources/ScriptoriaApp/Views/`
- App state: `Sources/ScriptoriaApp/AppState.swift`
Expand Down
11 changes: 10 additions & 1 deletion Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ let package = Package(
dependencies: [
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.5.0"),
.package(url: "https://github.com/groue/GRDB.swift.git", from: "7.0.0"),
.package(url: "https://github.com/jpsim/Yams.git", from: "6.0.1"),
],
targets: [
// Shared core library
.target(
name: "ScriptoriaCore",
dependencies: [
.product(name: "GRDB", package: "GRDB.swift"),
.product(name: "Yams", package: "Yams"),
],
path: "Sources/ScriptoriaCore"
),
Expand Down
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ A full-featured command-line tool for terminal workflows and automation:
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" --model gpt-5.3-codex --no-steer
scriptoria flow validate ./flows/pr-check.yaml
scriptoria flow run ./flows/pr-check.yaml --var repo=org/repo --command "/interrupt"
scriptoria schedule add "Backup" --daily 09:00
scriptoria search "deploy"
scriptoria tags
Expand All @@ -35,6 +37,7 @@ scriptoria config show
| `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, optional post-script agent stage (`--model`, `--agent-prompt`, `--command`, `--skip-agent`) |
| `flow validate/compile/run/dry-run` | Validate, compile, execute, and fixture-drive Flow DSL (`flow/v1`) |
| `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 @@ -44,6 +47,34 @@ scriptoria config show
| `config show` | Show current configuration |
| `config set-dir <path>` | Change data directory |

### Flow DSL (`flow/v1`)

Scriptoria supports state-machine automation flows for gate/agent/wait/script loops.

```bash
# 1) Validate YAML
scriptoria flow validate ./flows/pr-check.yaml

# 2) Compile to canonical IR JSON
scriptoria flow compile ./flows/pr-check.yaml --out ./build/pr-check.flow.json

# 3) Execute with context overrides and command queue
scriptoria flow run ./flows/pr-check.yaml \
--var repo=org/repo \
--max-agent-rounds 10 \
--command "Please focus only on flaky tests"

# 4) Execute deterministic dry-run with fixture data
scriptoria flow dry-run ./flows/pr-check.yaml --fixture ./fixtures/pr-check.fixture.json
```

Flow docs:

- [Flow DSL v1 Guide](docs/flow-dsl-v1.md)
- [Flow v1 Migration Notes](docs/flow-migration-v1.md)
- [Flow v1 Examples](docs/examples/flow-v1/README.md)
- [Flow TC Mapping](docs/flow-tc-mapping.md)

### AI Agent Friendly

Scriptoria includes a reusable [skill](skills/scriptoria/SKILL.md) and a provider-agnostic agent runtime, so coding agents can manage scripts end to end.
Expand Down
58 changes: 31 additions & 27 deletions Scriptoria.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@
1101D4D75F95D6E5C61D9762 /* ScriptoriaApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 314C4B3F5DEE48EE23608935 /* ScriptoriaApp.swift */; };
14C5032478AD8E0E40750609 /* ScriptDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCD790DB86E129E5B8AAC27 /* ScriptDetailView.swift */; };
18730951A4D97AAD6F17FC0C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8734D3C6C6D80C25E8EE3EFA /* AppDelegate.swift */; };
6836D847EB2FB81F93BF6865 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7828AA1B9D9E8F4ABB338426 /* SettingsView.swift */; };
82326E1EF91940E0E56DA13C /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41F53EBF447399BC36FEC18B /* AppState.swift */; };
AD4CC9D6D339E6656981A49C /* ScheduleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 926885C9F5B17D4FE43B7DED /* ScheduleView.swift */; };
6836D847EB2FB81F93BF6865 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7828AA1B9D9E8F4ABB338426 /* SettingsView.swift */; };
82326E1EF91940E0E56DA13C /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41F53EBF447399BC36FEC18B /* AppState.swift */; };
A19A8E4D1C2B4F0AA66D2F11 /* FlowWorkbenchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A19A8E4C1C2B4F0AA66D2F11 /* FlowWorkbenchView.swift */; };
AD4CC9D6D339E6656981A49C /* ScheduleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 926885C9F5B17D4FE43B7DED /* ScheduleView.swift */; };
B76B2B08A4F11C853B7B7777 /* AllSchedulesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FDC65F4310EFA49277C47E8 /* AllSchedulesView.swift */; };
C6CCFA4BA9270DC3DF63F9AF /* AddScriptSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1B5C87085FA75C7D7F4F73F /* AddScriptSheet.swift */; };
ED30B7341DB4D991E93A9333 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1E48F0320DA436D78535A30 /* Theme.swift */; };
Expand All @@ -26,9 +27,10 @@
001CC86E19769AC65E40D004 /* Scriptoria.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Scriptoria.entitlements; sourceTree = "<group>"; };
2925628068564CA6706DC15D /* OnboardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingView.swift; sourceTree = "<group>"; };
2FDC65F4310EFA49277C47E8 /* AllSchedulesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllSchedulesView.swift; sourceTree = "<group>"; };
314C4B3F5DEE48EE23608935 /* ScriptoriaApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptoriaApp.swift; sourceTree = "<group>"; };
41F53EBF447399BC36FEC18B /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = "<group>"; };
534A295C452035CF45B5B0D6 /* MainWindowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainWindowView.swift; sourceTree = "<group>"; };
314C4B3F5DEE48EE23608935 /* ScriptoriaApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptoriaApp.swift; sourceTree = "<group>"; };
41F53EBF447399BC36FEC18B /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = "<group>"; };
A19A8E4C1C2B4F0AA66D2F11 /* FlowWorkbenchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlowWorkbenchView.swift; sourceTree = "<group>"; };
534A295C452035CF45B5B0D6 /* MainWindowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainWindowView.swift; sourceTree = "<group>"; };
7828AA1B9D9E8F4ABB338426 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
8734D3C6C6D80C25E8EE3EFA /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
8F1189A738FE4A29534EEF76 /* Scriptoria.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Scriptoria.app; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -94,16 +96,17 @@
path = Views;
sourceTree = "<group>";
};
DB167BE26AF0E99D5C017456 /* Main */ = {
isa = PBXGroup;
children = (
C1B5C87085FA75C7D7F4F73F /* AddScriptSheet.swift */,
2FDC65F4310EFA49277C47E8 /* AllSchedulesView.swift */,
534A295C452035CF45B5B0D6 /* MainWindowView.swift */,
2925628068564CA6706DC15D /* OnboardingView.swift */,
926885C9F5B17D4FE43B7DED /* ScheduleView.swift */,
DBCD790DB86E129E5B8AAC27 /* ScriptDetailView.swift */,
7828AA1B9D9E8F4ABB338426 /* SettingsView.swift */,
DB167BE26AF0E99D5C017456 /* Main */ = {
isa = PBXGroup;
children = (
C1B5C87085FA75C7D7F4F73F /* AddScriptSheet.swift */,
2FDC65F4310EFA49277C47E8 /* AllSchedulesView.swift */,
A19A8E4C1C2B4F0AA66D2F11 /* FlowWorkbenchView.swift */,
534A295C452035CF45B5B0D6 /* MainWindowView.swift */,
2925628068564CA6706DC15D /* OnboardingView.swift */,
926885C9F5B17D4FE43B7DED /* ScheduleView.swift */,
DBCD790DB86E129E5B8AAC27 /* ScriptDetailView.swift */,
7828AA1B9D9E8F4ABB338426 /* SettingsView.swift */,
);
path = Main;
sourceTree = "<group>";
Expand Down Expand Up @@ -186,17 +189,18 @@
/* End PBXProject section */

/* Begin PBXSourcesBuildPhase section */
D848BC60306948A79CC99449 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C6CCFA4BA9270DC3DF63F9AF /* AddScriptSheet.swift in Sources */,
B76B2B08A4F11C853B7B7777 /* AllSchedulesView.swift in Sources */,
18730951A4D97AAD6F17FC0C /* AppDelegate.swift in Sources */,
82326E1EF91940E0E56DA13C /* AppState.swift in Sources */,
F8965BFC7FD0BC00A237F7C0 /* MainWindowView.swift in Sources */,
10D0C80B4E79E74F06C31D90 /* MenuBarPanel.swift in Sources */,
F27F0388CC886AA0ECAE97F0 /* OnboardingView.swift in Sources */,
D848BC60306948A79CC99449 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C6CCFA4BA9270DC3DF63F9AF /* AddScriptSheet.swift in Sources */,
B76B2B08A4F11C853B7B7777 /* AllSchedulesView.swift in Sources */,
A19A8E4D1C2B4F0AA66D2F11 /* FlowWorkbenchView.swift in Sources */,
18730951A4D97AAD6F17FC0C /* AppDelegate.swift in Sources */,
82326E1EF91940E0E56DA13C /* AppState.swift in Sources */,
F8965BFC7FD0BC00A237F7C0 /* MainWindowView.swift in Sources */,
10D0C80B4E79E74F06C31D90 /* MenuBarPanel.swift in Sources */,
F27F0388CC886AA0ECAE97F0 /* OnboardingView.swift in Sources */,
AD4CC9D6D339E6656981A49C /* ScheduleView.swift in Sources */,
14C5032478AD8E0E40750609 /* ScriptDetailView.swift in Sources */,
1101D4D75F95D6E5C61D9762 /* ScriptoriaApp.swift in Sources */,
Expand Down
Loading
Loading