Skip to content

Commit 033d056

Browse files
authored
Merge pull request #100 from ScriptKittyOS/docs/readme-visuals
docs: show the permission gate and the decision receipts in the README
2 parents 8f64f47 + 75b61a4 commit 033d056

4 files changed

Lines changed: 55 additions & 0 deletions

File tree

‎README.md‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,23 @@ reaches you on whatever surface you are using, and does not lose your work when
3535
Trinity is built on Elixir and the BEAM, with Phoenix LiveView for the interface, and ships as a
3636
desktop application. Apache-2.0, developed in the open from the first commit.
3737

38+
## What it looks like
39+
40+
**It asks before it acts, and it shows you exactly what it is asking for.** Not the tool's name and a
41+
shrug: the arguments it will actually pass, the risk tier, and a pattern you can widen if you want
42+
this answered once instead of every time.
43+
44+
![Trinity asking permission to run a write-risk tool, showing the exact arguments, the WRITE risk tier, and the four decisions available](docs/assets/approval-card.png)
45+
46+
**Then the decision is receipted, whichever way it went.** Both halves are written to a hash-linked,
47+
signed chain: the gate asking because no rule covered the call, and the answer you gave. The verifier
48+
reads this chain without the application running, so an auditor does not have to trust the program
49+
that wrote the records.
50+
51+
![Two signed decision receipts for the same call: the gate asking with basis=default outcome=ask, and the owner allowing with basis=approval outcome=allow](docs/assets/receipts-decision.png)
52+
53+
Both are real screens from a running build, captured by `scripts/dev_demo_approval.sh`.
54+
3855
## Status
3956

4057
Pre-alpha, and usable from source. Milestones **M0** to **M4** are approved, **M5a Automates** with

‎docs/assets/approval-card.png‎

67.1 KB
Loading

‎docs/assets/receipts-decision.png‎

33.1 KB
Loading

‎scripts/dev_demo_approval.sh‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#!/usr/bin/env bash
2+
# SPDX-FileCopyrightText: Sudo Apt Holdings LLC
3+
# SPDX-License-Identifier: Apache-2.0
4+
# The chat on the test registry (the fake provider, the test tools, a scripted turn that calls
5+
# the write-risk tool) for the slice 021 screenshots and the owner's manual queue. The test
6+
# environment's Repo without its sandbox pool and with the check_origin off, the application
7+
# started by hand; the port is printed as PORT=<n>. Run `mix assets.build` first, and remove
8+
# any stale `priv/static/assets/**/*.gz` (Plug.Static serves the gzip in this environment).
9+
# Its database is trinity_screenshots.db, never the test suite's: rows written outside the
10+
# sandbox broke four usage_events tests once (slice 021 NOTES).
11+
cd "$(dirname "$0")/.."
12+
export MIX_ENV=test
13+
exec systemd-run --user --scope -p MemoryMax=32G --quiet -- mix run --no-start --no-halt -e '
14+
repo = Application.get_env(:trinity, Trinity.Repo) |> Keyword.delete(:pool) |> Keyword.put(:database, "trinity_screenshots.db")
15+
Application.put_env(:trinity, Trinity.Repo, repo)
16+
endpoint = Application.get_env(:trinity, TrinityWeb.Endpoint) |> Keyword.put(:check_origin, false)
17+
Application.put_env(:trinity, TrinityWeb.Endpoint, endpoint)
18+
Application.put_env(:trinity, :permissions, expiry_ms: 600_000, session_grant_ms: 3_600_000)
19+
# The suite sets tools timeout_ms: 2_000, right for tests and impossible for a person: an approval
20+
# that waits on a human always expires and the turn records the tool as timed out. A minute here.
21+
tools = Application.get_env(:trinity, :tools, [])
22+
Application.put_env(:trinity, :tools, Keyword.put(tools, :timeout_ms, 60_000))
23+
# Migrate before the application starts, not after. Oban is a supervised child and its tables
24+
# must exist by the time it boots; running the migrator afterwards only ever appeared to work
25+
# because a previous run had left a migrated file behind, and it fails outright on a fresh one.
26+
for repo <- [Trinity.Repo, Trinity.Repo.Receipts] do
27+
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, all: true))
28+
end
29+
{:ok, _} = Application.ensure_all_started(:trinity)
30+
call = [{:text_delta, "I will save that as a note. "}, {:sleep, 300}, {:tool_call_start, "c1", "write_note"}, {:tool_call_end, "c1", %{"path" => "/home/me/notes/today.md", "text" => "Buy oat milk, call the dentist, finish the slice."}}, {:usage, %{input_tokens: 12, output_tokens: 20}}, {:done, :tool_calls}]
31+
final = fn text -> Enum.flat_map(String.split(text), &[{:text_delta, &1 <> " "}, {:sleep, 40}]) ++ [{:usage, %{input_tokens: 40, output_tokens: 30}}, {:done, :stop}] end
32+
# The pair repeated: each capture run consumes one call and one answer, and a second run on the
33+
# same server otherwise gets an empty script and a turn that ends instantly at idle.
34+
answer = final.("Saved. The note is at **/home/me/notes/today.md** with three items: oat milk, the dentist, and the slice.")
35+
Trinity.LLM.Providers.Fake.scripts(Enum.concat(List.duplicate([call, answer], 6)))
36+
{:ok, {_, port}} = TrinityWeb.Endpoint.server_info(:http)
37+
IO.puts("PORT=#{port}")
38+
'

0 commit comments

Comments
 (0)