A notch for Windows: a top-centre always-on-top pill that pops out cards (questions, tasks, facts, permissions) from local agents and reports your clicks back over a loopback API.
pks-agent-notch [--bottom] | pks-agent-notch demo [--show] [--scene <name>] [--list] | pks-agent-notch --version | pks-agent-notch --help$ pks-agent-notchStart the notch at the top of the primary screen (one instance; a second start exits)
$ pks-agent-notch --bottomStart it docked at the bottom, over the taskbar
$ pks exec pks-agent-notchLaunch it through pks; the discovery manifest declares no capabilities, so nothing is asked
$ pks-agent-notch demo | Out-HostScripted tour of every card kind, a five-field question, ttl, replace, reply_to, the answer API and history — PASS/FAIL per scene, exit 0/1
$ pks-agent-notch demo --showThe same tour with no expectations, paced for a screen recording
$ curl -s -X POST http://127.0.0.1:$(cat $LOCALAPPDATA/pks-notch/port)/v1/cards -d '{"source":"demo","kind":"spørgsmål","title":"Virker det?","actions":[{"id":"yes","label":"Ja"}]}'Post a card from anything local
A Mac-notch-style pill at the top centre of your Windows screen. Agents and tools on the same machine post cards to it; you see each card pop out for a few seconds, hover to see them all, and click a button to answer. The notch never takes focus from the window you are typing in, so an agent in a terminal you cannot see can still ask.
A card with fields is a question: the person types or picks the answer on the card
itself, and the asking tool reads it back by id. Cards have a kind that sets the badge colour: spørgsmål (orange), opgave
(amber), fakta and info (muted), svar (green), tilladelse (red). The pill reads
● <source> · N kort, or ● <source> · 1 spørgsmål · N kort while something waits for an answer.
irm https://agentics.dk/install/pks-agent-notch.ps1 | iex
pks-agent-notch
Windows 10/11, x64. Self-contained single file; nothing else to install.
| Command | Does |
|---|---|
pks-agent-notch | Start at the top of the primary screen |
pks-agent-notch --bottom | Start docked at the bottom |
pks-agent-notch --version | Print the version |
pks-agent-notch --help | Print the usage |
pks exec pks-agent-notch | Same, launched by pks (no provider is needed, so none is asked) |
pks-agent-notch demo | Out-Host | A scripted tour against the running notch (started if needed): PASS/FAIL per scene, exit 0 only when all passed |
pks-agent-notch demo --show | The same tour, no expectations, paced for a recording (--pace <s>) |
pks-agent-notch demo --scene <name> | One scene; --list names them; --timeout <s> is how long a scene waits for your click (90) |
A plain start prints nothing: the notch is a window without a console. What you should
see is the pill at the top of the screen and a tray icon. When neither appears, read
%LOCALAPPDATA%\pks-notch\notch.log — every start, exit and unhandled exception is a
line there.
pks-agent-notch demo is the acceptance test, the product demo and a reference client in
one. Ten scenes: health (the health document and the 404 route list), kinds (all six
kinds live at once, then deleted), klik (you click one of two buttons — status and the
SSE event must agree), luk (you close a tilladelse with ✕ → dismissed), ttl
(ttl_s → expired), erstat (same id twice → one card, the first replaced in
history), felter (a question with all five field types — you fill it in), svar-api
(POST …/answer: 400 without the required value, 200 with it, 409 the second time),
reply-to (a loopback listener receives the status; http://example.com is refused) and
historik (every card of the run, with outcome and values). Pipe it from PowerShell
(| Out-Host) or run it as pks exec pks-agent-notch demo — a window app otherwise hands
the prompt back at once. Exit codes: 0 all passed · 1 a scene failed · 2 no notch to talk
to · 3 bad flags.
Right-click the notch, or the tray icon: Dock top · Dock bottom · Afslut.
Hover for the full list; the ✕ chip top-right hides the notch to a sliver until the
next card (at least 10 s).
While it runs, the notch serves http://127.0.0.1:<port>/ and writes the port to
%LOCALAPPDATA%\pks-notch\port (one line; deleted on exit).
$port = Get-Content "$env:LOCALAPPDATA\pks-notch\port"
$base = "http://127.0.0.1:$port"
| Route | Does |
|---|---|
POST /v1/cards | {id?, source, kind, title, text?, fields?, actions?:[{id,label,role?}], ttl_s?, reply_to?} → 201 {id}. An existing id replaces the card in place. |
GET /v1/cards | The current list, newest first |
GET /v1/cards/{id} | The card and its state (pending · answered · dismissed · expired · deleted), with answer: {action, values} once it ended |
POST /v1/cards/{id}/answer | {action?, values?} — answer on the person's behalf, same validation as the screen → 200 status |
DELETE /v1/cards/{id} | Remove a card → 204 |
GET /v1/events | text/event-stream: event: action with {"card","action","source","values"?} on every click or answer, ✕ included as dismiss; : keepalive every 15 s |
GET /v1/history | The last 500 cards that ended, with outcome, resolved_at and values |
GET /v1/health | {version, cards, questions, history, uptime_s} |
A card with fields is a question the person answers on the card: text (placeholder,
suggestions, multiline), choice (one of), multi (any of), toggle (ja/nej), number
(min/max). The submit action is dimmed until the required fields are filled; a
secondary action ("Senere") sends whatever is there. Read the answer back from
GET /v1/cards/{id}, the event stream, or give a reply_to URL (https:// anywhere,
http:// only on this machine) and the notch POSTs the status when the card ends.
Invoke-RestMethod -Method Post -Uri "$base/v1/cards" -ContentType 'application/json' -Body '{
"id":"voice-1","source":"heypoul","kind":"spørgsmål","title":"Hvem er det, der taler?",
"text":"Ukendt stemme i 70 s.",
"fields":[{"id":"name","type":"text","label":"Navn","required":true,"suggestions":["Anders Hjorth","Malthe Schou"]},
{"id":"keep","type":"toggle","label":"Gem stemmen","default":true}],
"actions":[{"id":"save","label":"Gem"},{"id":"later","label":"Senere"}],"ttl_s":900}'
Invoke-RestMethod "$base/v1/cards/voice-1"
# state: answered, answer: {action: save, values: {name: "Anders Hjorth", keep: true}}
Post a question and wait for the answer:
Invoke-RestMethod -Method Post -Uri "$base/v1/cards" -ContentType 'application/json' -Body '{
"id":"q-1","source":"demo","kind":"spørgsmål","title":"Skal vi sende tilbuddet mandag?",
"actions":[{"id":"yes","label":"Ja, mandag"},{"id":"later","label":"Senere"}],"ttl_s":120}'
curl.exe -sN "$base/v1/events"
# event: action
# data: {"card":"q-1","action":"yes","source":"demo"}
A click resolves the card (it leaves the list) before the event is sent; re-POST with
the same id to keep it. English kind names (question, task, fact, answer,
permission, info) are accepted and stored as the Danish ones. No auth in v0:
loopback, same user.
The full contract with every status code is in the repo's docs/protocol.md.
Anything that can do an HTTP POST on the same machine is a source.