silas 0.5.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +145 -0
- data/DEPLOY.md +111 -0
- data/README.md +87 -256
- data/app/helpers/silas/inbox/trace_helper.rb +29 -6
- data/app/models/concerns/silas/inbox/broadcastable.rb +12 -0
- data/app/views/layouts/silas/inbox.html.erb +89 -30
- data/app/views/silas/inbox/invocations/_approval_card.html.erb +11 -2
- data/app/views/silas/inbox/invocations/_invocation.html.erb +17 -5
- data/app/views/silas/inbox/sessions/_cost.html.erb +3 -1
- data/app/views/silas/inbox/sessions/_row.html.erb +14 -0
- data/app/views/silas/inbox/sessions/index.html.erb +16 -15
- data/app/views/silas/inbox/sessions/show.html.erb +10 -1
- data/app/views/silas/inbox/turns/_header.html.erb +31 -25
- data/app/views/silas/inbox/turns/_turn.html.erb +5 -3
- data/docs/agents.md +81 -0
- data/docs/budgets.md +67 -0
- data/docs/cancellation.md +41 -0
- data/docs/channels.md +290 -0
- data/docs/configuration.md +106 -0
- data/docs/connections.md +58 -0
- data/docs/conventions.md +161 -0
- data/docs/evals.md +95 -0
- data/docs/guarantees.md +76 -0
- data/docs/inbox-and-api.md +91 -0
- data/docs/memory.md +35 -0
- data/docs/sandbox.md +44 -0
- data/docs/tools.md +77 -0
- data/docs/tutorial.md +272 -0
- data/docs/vs-eve.md +93 -0
- data/docs/why-silas.md +87 -0
- data/lib/generators/silas/install/install_generator.rb +9 -0
- data/lib/generators/silas/install/templates/claude_skill.md +136 -0
- data/lib/generators/silas/install/templates/ruby_llm.rb +4 -1
- data/lib/silas/connection.rb +16 -0
- data/lib/silas/eval/dsl.rb +7 -2
- data/lib/silas/version.rb +1 -1
- metadata +22 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d6fb5d6a2e04f91a4bc0ac0569a37da43017f6adae7209148878a2cb8ac41a66
|
|
4
|
+
data.tar.gz: 9d8ed143aac8d96d264a10ed3cf87c8ecee1ed838ba01ca67075a4a9a07e3b09
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e01f7110a093b91b30af1c08d4d8167aaaa24861812702c10ba5078f952e7eea4ddb5851e484f6cb2815d171271de9a45d8b7cc275e3d59dcaa2541ad9731628
|
|
7
|
+
data.tar.gz: c84142c165b45db56d5761a64a62993e7332a2209593ff1c59afd58723beafc5e2bd2c14f1495fbb8963d664a69469f28829dece7d6e973e8a5e123963ca526b
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,150 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.1 (2026-07-26)
|
|
4
|
+
|
|
5
|
+
Two live-inbox fixes found by driving real apps, a security hardening pass,
|
|
6
|
+
and the polished brand kit.
|
|
7
|
+
|
|
8
|
+
### Changed
|
|
9
|
+
|
|
10
|
+
- **Polished brand geometry everywhere.** Lamps sit on a shared r4.8 circle
|
|
11
|
+
(proceed and held aspects now one geometry), the favicon is redrawn
|
|
12
|
+
natively at 32px with a heavier housing (it reads at 16px now), and the
|
|
13
|
+
wordmark lockup is cropped to the ink — re-outlined to font-independent
|
|
14
|
+
paths on the new geometry. The inbox layout's favicon and header mark
|
|
15
|
+
carry the new coordinates, as do the templates' landing pages.
|
|
16
|
+
- The docs gained real product imagery: an 18-frame park→approve→clear GIF
|
|
17
|
+
captured from a genuine template-app run, the held approval card, and the
|
|
18
|
+
signal board — on the site landing, inbox-and-api, and tutorial pages.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- **The turn pill now flips to held live.** Turbo `replace` swaps the target
|
|
23
|
+
element itself, but the header's and cost line's broadcast-target ids lived
|
|
24
|
+
on wrapper divs in the parent views — so the FIRST status broadcast
|
|
25
|
+
destroyed the target and every later one (including the park that reads
|
|
26
|
+
**held**) silently no-opped until a reload. The partials now carry their own
|
|
27
|
+
root ids, with regression specs asserting a replace re-emits its target.
|
|
28
|
+
- **The first broadcast of a fresh worker no longer dies on lazy routes.**
|
|
29
|
+
Rails 8.1's lazy route set only retries a missing url helper when the app
|
|
30
|
+
routes were *just* loaded; in a worker's first Turbo render the engine's
|
|
31
|
+
helper module could predate its route draw, killing the job silently
|
|
32
|
+
(`undefined method 'cancel_inbox_turn_path'`). `silas_engine_path` now
|
|
33
|
+
forces the draw once on miss.
|
|
34
|
+
|
|
35
|
+
### Security
|
|
36
|
+
|
|
37
|
+
- **Connections refuse credentials over plaintext http.** A connection with
|
|
38
|
+
`auth:` configured and an `http://` URL to a remote host now fails loudly at
|
|
39
|
+
parse time (localhost exempt; unparseable URLs with auth fail closed).
|
|
40
|
+
Finding from the pre-release security audit — which otherwise confirmed the
|
|
41
|
+
posture: fail-closed HMAC webhook verification with constant-time compare
|
|
42
|
+
and a replay window, expiring signed approval tokens, deny-by-default
|
|
43
|
+
inbox/API auth enforced at the base controllers, argv-array sandbox exec
|
|
44
|
+
(no shell interpolation), timing-safe MCP token compare, restricted ERB
|
|
45
|
+
bindings, no interpolated SQL, Brakeman and bundler-audit clean.
|
|
46
|
+
|
|
47
|
+
## 0.6.0 (2026-07-26)
|
|
48
|
+
|
|
49
|
+
The brand release: the Signals inbox, the docs surface (site + gem-shipped
|
|
50
|
+
guides + tutorial), the templates family (desk + analyst) with its anti-rot
|
|
51
|
+
CI gate, community files, and the framework-first README.
|
|
52
|
+
|
|
53
|
+
### Added
|
|
54
|
+
|
|
55
|
+
- **Docs for the whole surface.** New guides, all shipped in the gem:
|
|
56
|
+
`tutorial` (build the refund desk outward, one primitive per chapter),
|
|
57
|
+
`guarantees`, `tools`, `agents`, `memory`, `inbox-and-api`, `sandbox`,
|
|
58
|
+
`evals`, `budgets`, `cancellation`, `connections`, and a full
|
|
59
|
+
`configuration` reference. A docs site (Jekyll + just-the-docs, dark-first,
|
|
60
|
+
Archivo/Space Mono, `early · 0.x` chip) builds from `docs/` in CI and
|
|
61
|
+
deploys to Pages, with an `llms.txt` for coding agents. Brand assets
|
|
62
|
+
(`brand/`, hero at `docs/img/`) now live in the repo; the hero image is
|
|
63
|
+
excluded from the packaged gem.
|
|
64
|
+
- **Rails application templates, as a family** — `templates/desk.rb` and
|
|
65
|
+
`templates/analyst.rb`, each a single CI-gated `rails new -m` script.
|
|
66
|
+
`rails new desk -m
|
|
67
|
+
https://raw.githubusercontent.com/danielstpaul/silas/main/templates/desk.rb`
|
|
68
|
+
builds a deployable agent app from nothing: a refund desk with one tool per effect
|
|
69
|
+
mode (`lookup_order` idempotent, `issue_refund` transactional behind a
|
|
70
|
+
£25 approval gate, `notify_customer` at-most-once), Solid Queue **and** Solid
|
|
71
|
+
Cable wired in development (the durability contract needs a real worker; live
|
|
72
|
+
deltas need a cross-process cable), a keyless scripted stand-in so the first
|
|
73
|
+
`bin/dev` works with zero secrets, three deterministic agent evals asserting
|
|
74
|
+
the hold and the exactly-once execution, and a Signals-branded signal-board
|
|
75
|
+
landing page. The template only runs the generators the gem already tests,
|
|
76
|
+
and the `templates_smoke` workflow regenerates and tests an app from every
|
|
77
|
+
template on each push — starters that structurally cannot rot. (eve needs
|
|
78
|
+
template repos because it has no generator story; Rails has application
|
|
79
|
+
templates.) **The analyst** is the second template: a scheduled reporting
|
|
80
|
+
agent — `query_metrics` reads, `flag_anomaly` lands rows exactly once,
|
|
81
|
+
`publish_report` holds at the signal (`approval :always`), a Monday-07:00
|
|
82
|
+
schedule, and a schema-checked `final_answer` (`Turn#answer_data`). Both
|
|
83
|
+
templates also wire `ANTHROPIC_API_KEY` into Kamal's secrets so the
|
|
84
|
+
generated app deploys without a scavenger hunt.
|
|
85
|
+
- **Community files** — `CONTRIBUTING.md` (the deliberate scope no-list, the
|
|
86
|
+
chaos-gate requirement, how templates are contributed), `SECURITY.md`
|
|
87
|
+
(private vulnerability reporting; deny-by-default surfaces; contract
|
|
88
|
+
violations count), and GitHub issue forms.
|
|
89
|
+
- **The gem ships its own docs, and the installer ships a coding-agent skill.**
|
|
90
|
+
`docs/**` and `DEPLOY.md` are in the packaged gem, so `bundle show silas`
|
|
91
|
+
gives a coding agent (or an offline human) the real reference — and the
|
|
92
|
+
README's links stop 404ing for gem-only readers. `rails g silas:install` now
|
|
93
|
+
also writes `.claude/skills/silas/SKILL.md`: the `app/agent/` conventions,
|
|
94
|
+
the effect-mode and approval decision rules, and the ledger rules an agent
|
|
95
|
+
must never violate — so a Claude Code/Codex session building on this app
|
|
96
|
+
gets the framework's judgment without the human learning it first. Gemspec
|
|
97
|
+
gains `documentation_uri` and `bug_tracker_uri`.
|
|
98
|
+
|
|
99
|
+
### Changed
|
|
100
|
+
|
|
101
|
+
- **The inbox wears the brand** (direction "Signals"). Dark-first — the tokens'
|
|
102
|
+
base is the night palette and light is the `prefers-color-scheme` override —
|
|
103
|
+
with a position-light mark, a lowercase wordmark, and one white "lamp" accent
|
|
104
|
+
that never means state. The seven run states each get their aspect:
|
|
105
|
+
`in_doubt` its own violet (it is neither waiting-by-design nor failed),
|
|
106
|
+
`canceled` a dashed quiet (a lamp going out, not turning red), and two
|
|
107
|
+
UI-only relabels — `waiting` reads **held**, `completed` reads **clear**. The
|
|
108
|
+
database strings and the JSON API are untouched (`docs/conventions.md`).
|
|
109
|
+
- **Approvals and questions are hoisted to the top of the session** — the
|
|
110
|
+
operator never scrolls a long trace hunting for the card; the trace keeps a
|
|
111
|
+
one-line "held at the signal" stub in place. Live parks append their card via
|
|
112
|
+
the same Turbo broadcasts; settled cards remove themselves. Tool arguments
|
|
113
|
+
render as key/value rows and results collapse behind a disclosure; the
|
|
114
|
+
session index groups its rail by who's blocked: **Held / Working / Filed**.
|
|
115
|
+
- The playground's chat page consumes the engine's colour tokens instead of
|
|
116
|
+
re-hardcoding a palette, and hosts the hoisted approval/question cards above
|
|
117
|
+
its transcript.
|
|
118
|
+
|
|
119
|
+
- **README reframed, framework-first** — it now mirrors eve's shape exactly:
|
|
120
|
+
the mark as the logo (dark/light `<picture>`), badges, a one-paragraph
|
|
121
|
+
thesis, "The filesystem is the authoring interface" with the tree, quick
|
|
122
|
+
start, one minimal example, status/community/license. The hero illustration
|
|
123
|
+
moved to the repo's social-preview role (its inbox panel is a designed
|
|
124
|
+
idealization, not a screenshot — it shouldn't sit where users compare it to
|
|
125
|
+
the real `/silas/inbox`). The docs site nav is grouped eve-style — Tutorial
|
|
126
|
+
and Guarantees up top, then **Core / Advanced / Reference / About**
|
|
127
|
+
sections — via build-time frontmatter injection (`site/assemble.rb`, which
|
|
128
|
+
fails the build if a docs page lacks a nav entry), keeping the gem-shipped
|
|
129
|
+
markdown frontmatter-free. `docs/vs-eve.md` was **factually rewritten**
|
|
130
|
+
(2026-07-26): the previous revision described eve as a managed-cloud
|
|
131
|
+
platform; eve is fully self-hostable, and the comparison now rests on what's
|
|
132
|
+
actually different — exactly-once vs documented at-least-once, a shipped
|
|
133
|
+
production inbox vs a dev TUI, memory vs none, and the transaction-boundary
|
|
134
|
+
argument, date-stamped against eve 0.27.6 and framed as siblings (pick by
|
|
135
|
+
stack). `docs/why-silas.md` rewritten in the same voice — you build the same
|
|
136
|
+
things with Silas you'd build with any modern agent framework; the
|
|
137
|
+
guarantees are where it goes further — and DEPLOY.md dropped its stale "eve
|
|
138
|
+
without the bill" subtitle.
|
|
139
|
+
|
|
140
|
+
### Fixed
|
|
141
|
+
|
|
142
|
+
- The generated `config/initializers/ruby_llm.rb` no longer guards its whole
|
|
143
|
+
configure block behind `ANTHROPIC_API_KEY` — keyless boots skipped the
|
|
144
|
+
`use_new_acts_as` opt-in, so every demo-mode boot printed RubyLLM's legacy
|
|
145
|
+
acts_as deprecation warning. A nil key assignment is inert; the block now
|
|
146
|
+
always runs.
|
|
147
|
+
|
|
3
148
|
## 0.5.0 (2026-07-26)
|
|
4
149
|
|
|
5
150
|
Two new loop primitives (replay-safe compaction, ask_question), a whole-channel
|
data/DEPLOY.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Deploying Silas
|
|
2
|
+
|
|
3
|
+
A Silas app is an ordinary Rails app, so it deploys the way your Rails apps
|
|
4
|
+
already deploy — a single cheap VPS with Kamal works fine; there is no second
|
|
5
|
+
runtime or control plane to stand up. The one thing you MUST get right: the
|
|
6
|
+
**Solid Queue worker has to run**, because the durability contract (a turn
|
|
7
|
+
surviving a crash / deploy) depends on it. A web-only deploy will accept turns
|
|
8
|
+
and never run them.
|
|
9
|
+
|
|
10
|
+
> Status: this is the reference configuration. It is correct by construction
|
|
11
|
+
> (worker wired, rescuer active, secrets injected) but has not yet been run
|
|
12
|
+
> against a live VPS end-to-end — that's the final launch step.
|
|
13
|
+
|
|
14
|
+
## 1. The worker must run
|
|
15
|
+
|
|
16
|
+
> **Queue adapter: use Solid Queue.** Silas's durability and exactly-once
|
|
17
|
+
> guarantees require a durable, serializing, DB-backed adapter. **Do not run on
|
|
18
|
+
> the in-process `:async` adapter** (Rails' development default) — it runs
|
|
19
|
+
> continuation retries on a thread pool concurrently with the original job,
|
|
20
|
+
> which double-executes steps and breaks exactly-once. Silas warns at boot if it
|
|
21
|
+
> detects the Async adapter. For scripts and single-process demos, the
|
|
22
|
+
> synchronous `:inline` adapter is safe (but has no durability).
|
|
23
|
+
|
|
24
|
+
`rails g silas:install` already appends the durability rescuer to
|
|
25
|
+
`config/recurring.yml`:
|
|
26
|
+
|
|
27
|
+
```yaml
|
|
28
|
+
production:
|
|
29
|
+
silas_dead_job_rescuer: # retries jobs failed by dead-worker reaping/pruning
|
|
30
|
+
class: Silas::DeadJobRescuerJob
|
|
31
|
+
schedule: every 30 seconds
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Pick one way to run Solid Queue:
|
|
35
|
+
|
|
36
|
+
- **Simple (one container):** run the worker inside Puma —
|
|
37
|
+
set `SOLID_QUEUE_IN_PUMA=true` (Rails 8 default plugin). Fine for a demo box.
|
|
38
|
+
- **Recommended (durable):** a dedicated `bin/jobs` process, so a `kill -9` of the
|
|
39
|
+
worker is isolated from the web tier and recovery is observable.
|
|
40
|
+
|
|
41
|
+
## 2. Kamal config (`config/deploy.yml`)
|
|
42
|
+
|
|
43
|
+
A standard `rails new` ships a Dockerfile and `config/deploy.yml`. Add a **job
|
|
44
|
+
role** so the worker is its own container:
|
|
45
|
+
|
|
46
|
+
```yaml
|
|
47
|
+
service: my-agent
|
|
48
|
+
image: you/my-agent
|
|
49
|
+
servers:
|
|
50
|
+
web:
|
|
51
|
+
- 1.2.3.4 # your £5/month VPS
|
|
52
|
+
job:
|
|
53
|
+
hosts:
|
|
54
|
+
- 1.2.3.4
|
|
55
|
+
cmd: bin/jobs # the Solid Queue worker (+ dispatcher + scheduler)
|
|
56
|
+
|
|
57
|
+
registry:
|
|
58
|
+
username: you
|
|
59
|
+
password:
|
|
60
|
+
- KAMAL_REGISTRY_PASSWORD
|
|
61
|
+
|
|
62
|
+
env:
|
|
63
|
+
secret:
|
|
64
|
+
- RAILS_MASTER_KEY
|
|
65
|
+
- ANTHROPIC_API_KEY # the :ruby_llm engine authenticates with this
|
|
66
|
+
clear:
|
|
67
|
+
SOLID_QUEUE_IN_PUMA: false # the job role runs the worker instead
|
|
68
|
+
|
|
69
|
+
# Persist SQLite + Solid Queue on a volume if you're using SQLite (or point at Postgres).
|
|
70
|
+
volumes:
|
|
71
|
+
- "my_agent_storage:/rails/storage"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Secrets (Slack signing secret / bot token, model keys) go in `.kamal/secrets`
|
|
75
|
+
(pulled from your env or a vault), never in the image.
|
|
76
|
+
|
|
77
|
+
## 3. Deploy
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
kamal setup # first time
|
|
81
|
+
kamal deploy # subsequent
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Mid-deploy safety is built in: a turn interrupted by the SIGTERM of a rolling
|
|
85
|
+
deploy re-enqueues and resumes (chaos-gated). Recovery latency after a hard
|
|
86
|
+
crash ≈ `SolidQueue.process_alive_threshold` + the rescuer's 30s cadence.
|
|
87
|
+
|
|
88
|
+
## 3½. Template apps deploy stock
|
|
89
|
+
|
|
90
|
+
An app generated from `templates/*.rb` needs no deploy surgery: Rails 8.1's
|
|
91
|
+
generated `config/deploy.yml` already runs Solid Queue inside Puma for the
|
|
92
|
+
single-server SQLite shape (`SOLID_QUEUE_IN_PUMA: true` — that satisfies "the
|
|
93
|
+
worker must run"), the template adds `ANTHROPIC_API_KEY` to Kamal's secret
|
|
94
|
+
list and `.kamal/secrets`, and `config/recurring.yml` already carries the
|
|
95
|
+
rescuer. Set the two secrets in your shell, point `deploy.yml` at your server
|
|
96
|
+
and registry, `kamal setup`. Scale beyond one box by moving to the dedicated
|
|
97
|
+
worker role in §1 and a real Postgres in §2.
|
|
98
|
+
|
|
99
|
+
## 4. Cost
|
|
100
|
+
|
|
101
|
+
The whole thing runs on one VPS + your model spend. The engine authenticates
|
|
102
|
+
with an API key for whatever provider you configure through RubyLLM. Your data
|
|
103
|
+
and the ledger never leave your own Postgres, and there is no Silas platform
|
|
104
|
+
bill or per-run metering.
|
|
105
|
+
|
|
106
|
+
## 5. Local development note (macOS + Postgres)
|
|
107
|
+
|
|
108
|
+
Solid Queue forks workers, and on macOS the pg gem needs
|
|
109
|
+
`PGGSSENCMODE=disable OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES` in the
|
|
110
|
+
environment or forked workers crash inside libpq. SQLite development needs
|
|
111
|
+
nothing.
|