From 403680ac3b46fa6b3f4e8af856a2e7201b9de64b Mon Sep 17 00:00:00 2001 From: simo787c <92300326+simo787c@users.noreply.github.com> Date: Mon, 27 Jul 2026 10:53:24 +0200 Subject: [PATCH 1/3] feat(browser): add byg-et-flow intake/build skill MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The build-from-scratch skill for agentbase-browser — the intake front half the MCP's guidance.py (mechanics canon) deliberately lacks. - skills/byg-et-flow/SKILL.md — interview → confirm the plan in chat → build → run on a real sample → iterate. Enforces a five-point intake bar before building (process+rules, variants, a real sample input, output+audience, Human-in-the-Loop placement) and the chat-checkpoint discipline (the canvas is invisible in another tab). Hands off to the MCP mechanics: read guide://flow-building, confirm handles with get_node_type, lay the whole graph in one set_flow rather than clobber-prone incremental edits. - skills/byg-et-flow/references/flow-eksempler.md — four Danish flow shapes distilled from guidance.py EXAMPLES + docs relationships.md (document → structured data → spreadsheet; sort a document pile; loop over a list; conditional branching), each pointing at the live example:// resource and get_node_type for exact handles, so tool-schema drift can't reach the skill. RED/GREEN tested: without the skill a fresh agent gathered only a partial intake (missed variants and the approval step); with it, the full five-point intake plus confirm-in-chat/run-on-sample loop. Co-Authored-By: Claude via Dash Claude-Session: https://claude.ai/code/session_01SYvwyQEa9xsKzsQTwpBuhp --- agentbase-browser/skills/byg-et-flow/SKILL.md | 51 ++++++++++++++++ .../byg-et-flow/references/flow-eksempler.md | 61 +++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 agentbase-browser/skills/byg-et-flow/SKILL.md create mode 100644 agentbase-browser/skills/byg-et-flow/references/flow-eksempler.md diff --git a/agentbase-browser/skills/byg-et-flow/SKILL.md b/agentbase-browser/skills/byg-et-flow/SKILL.md new file mode 100644 index 0000000..f5abbca --- /dev/null +++ b/agentbase-browser/skills/byg-et-flow/SKILL.md @@ -0,0 +1,51 @@ +--- +name: byg-et-flow +description: Interviewer brugeren og bygger et AgentBase-flow, der automatiserer en proces. Brug når brugeren vil automatisere en opgave eller bygge et flow/en agent — fx "byg et flow der ...", "jeg vil automatisere X", "kan du lave en agent der læser fakturaer", "lav noget der sorterer mine dokumenter". Kræver at AgentBase-værktøjerne er tilsluttet; er de ikke det, så kør kom-i-gang først. +--- + +# Byg et flow + +Du bygger et flow ved at **interviewe brugeren, bekræfte en plan i chatten, bygge +via AgentBase-værktøjerne, køre på en rigtig prøve og gentage.** Brugeren sidder +*ikke* og kigger på lærredet (det er i en anden fane) — så hvert holdepunkt skal +stå synligt i **chatten**, på klart dansk. + +## Før du bygger: intake — alle fem punkter + +Byg ikke, før du har dem. Mangler noget, så **spørg** — gæt aldrig. Et flow bygget +på ét eksempel passer til det ene eksempel, ikke til processen. + +1. **Processen i almindeligt sprog** + de regler, den følger. +2. **De forskellige situationer/varianter**, der findes i praksis (fx "faktura uden + momslinje", "scannet vs. digital PDF", "kontrakt dateret med ord"). +3. **Mindst ét rigtigt eksempel-input** at køre på. +4. **Hvad det færdige output er**, og hvem der læser det. +5. **Hvor det menneskelige godkendelsestrin** (Human-in-the-Loop) skal sidde — fx + før en faktura bogføres, eller et dokument sendes videre. + +## Byggeløkken + +1. **Interview** til alle fem intake-punkter er dækket. +2. **Bekræft planen i chatten.** Beskriv i klart dansk, hvilke byggeklodser flowet + får, og hvad det gør — og få et ja, *før* du bygger. Lærredet er usynligt for + brugeren, så teksten i chatten er deres eneste indblik. +3. **Byg.** Læs mekanikken fra MCP'ens egen vejledning (ressourcen + `guide://flow-building` og prompten `build_flow`), og se `references/flow-eksempler.md` + for en form at starte fra. Bekræft hvert trins præcise håndtag med `get_node_type` + — gæt aldrig navne. Læg **hele grafen i ét `set_flow`**; byg ikke inkrementelt + med `add_node`/`connect_nodes` (de læser-ændrer-skriver og overskriver hinanden). +4. **Kør på en rigtig prøve.** Vedhæft eksemplet, kør flowet, og vis brugeren det + *faktiske* output — ikke det, du gætter på, det gør. +5. **Gentag.** Vend tilbage til brugeren ved hver beslutning eller manglende + oplysning; ret og kør igen, til det er pålideligt. Stop ikke ved "gemt". + +## Holdepunkter skal stå i chatten + +Brugeren ser ikke lærredet. Derfor: bekræft planen i tekst før du bygger; efter en +kørsel — vis eller opsummér det rigtige output; og nævn åbent enhver antagelse, du +var nødt til at gøre. Sig aldrig bare "færdig" — vis resultatet. + +## Sprog + +Alt, brugeren ser (labels, instruktioner, skabelontekst, prompts), skrives på +**dansk**. Node-id'er kan være korte ASCII (fx `input_1`). diff --git a/agentbase-browser/skills/byg-et-flow/references/flow-eksempler.md b/agentbase-browser/skills/byg-et-flow/references/flow-eksempler.md new file mode 100644 index 0000000..64bb208 --- /dev/null +++ b/agentbase-browser/skills/byg-et-flow/references/flow-eksempler.md @@ -0,0 +1,61 @@ +# Flow-former at starte fra + +Genkendelige mønstre for AgentBase-flows. Brug dem til at foreslå brugeren en +form — vælg den, der passer til processen, og byg videre derfra. **Byggeklods- +navnene her er til orientering; bekræft altid de præcise håndtag (handles) med +`get_node_type`, og hent den kopiklare graf fra MCP'ens egne `example://`- +ressourcer.** MCP'ens `guide://flow-building` er den tekniske kanon. + +## 1. Dokument → struktureret data → regneark + +Læs et dokument, træk bestemte felter ud som struktureret data, og skriv dem i +faste kolonner i et regneark. + +- **Byggeklodser:** Dokument-OCR → Sprogmodel (med `response_schema`) → JSON til Excel. + Til mange filer på én gang: Dokumentliste → Fil til struktureret data → JSON til Excel. +- **Brug den til:** fakturaer, kontrakter eller ansøgninger, hvor bestemte felter + skal ud i faste kolonner. +- **MCP-eksempler:** `example://document-ocr-extract`, `example://file-to-structured`, + `example://json-to-excel`. + +## 2. Sortér en bunke dokumenter + +Upload mange blandede dokumenter, lad platformen klassificere hvert enkelt i en +kategori, du definerer, og træk valgfrie felter ud pr. kategori. + +- **Byggeklodser:** Sortér dokumenter (én output-kanal pr. kategori) → fx JSON til + Excel og/eller Sprogmodel (opsummering) pr. kategori. +- **Brug den til:** at rydde op i en blandet mappe af bilag, hvor hvert dokument + skal i den rigtige kasse. +- **MCP-eksempel:** `example://sort-documents`. + +## 3. Behandl hvert element i en liste (løkke) + +Gør det samme for hvert element i en liste — fx kør en sprogmodel på hver række +i et regneark eller hvert dokument i en bunke. + +- **Byggeklodser:** (kilde, fx CSV-parser) → Løkke Start → behandling (fx + Sprogmodel) → Løkke Slut (samler resultaterne). +- **Brug den til:** at anvende samme analyse på mange rækker, filer eller opslag. +- **MCP-eksempel:** `example://csv-enrich`. + +## 4. Betinget forgrening + +Send flowet ned ad forskellige veje afhængigt af en værdi. + +- **Byggeklodser:** Hvis / ellers (to grene, styret af en struktureret `config` — + ikke en sætning) eller Forgrening (flere grene efter værdi-match). Begge grene + føres typisk videre til samme næste trin — kun den gren, der matcher, giver output. +- **Brug den til:** at behandle sager forskelligt efter type, beløb eller status. +- **MCP-eksempel:** `example://if-else-branching` (og `guide://flow-building` for + den fulde `config`-form — den er ikke oplagt). + +## Almindelige faldgruber + +- **Brug ikke en kode-byggeklods (`python-code`) som type-oversætter.** Skal en fil + laves om til tekst, brug Dokument-OCR; skal tekst laves til JSON, brug Sprogmodel + med et `response_schema`. +- **Hvis / ellers** styres af en struktureret `config`, ikke en fritekst-sætning, + og begge grene (sand/falsk) skal føres videre. +- **Løkke-styring** (afbryd/spring over) hører til *inde* i en løkke. +- Skriv alt, brugeren ser (labels, instruktioner, skabelontekst, prompts), på dansk. From 3f37a8a17a774e63385db5951cfe0901baa54ef5 Mon Sep 17 00:00:00 2001 From: simo787c <92300326+simo787c@users.noreply.github.com> Date: Mon, 27 Jul 2026 10:56:48 +0200 Subject: [PATCH 2/3] feat(browser): add ret-et-flow debug/fix skill MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The debug skill for agentbase-browser — reproduce, localise, smallest fix, re-run. Mirrors the MCP's revise_flow prompt and folds in the concrete failure catalogue from guidance.py + flow-agent/src/prompts.ts. - skills/ret-et-flow/SKILL.md — the fault-finding loop (reproduce on a real failing input → localise the exact node:handle with get_execution → make the smallest change → re-run on the same input) plus a symptom→cause→fix table of the AgentBase-specific traps a generic agent won't know: empty output after a Hvis/ellers (config missing true_output/false_output → set both, route both branches to one shared field); raw {placeholder} (conditional branches merged into one template); dataurl→text needs Dokument-OCR not a code node; a list fed to a single-item node needs a Løkke; loop-control nodes must sit inside the loop; missing response_schema. Names no tool schemas — get_node_type and guide://flow-building stay the live source, so drift can't reach it. RED/GREEN tested on an empty-if-else-output scenario: both baseline and skilled agents debugged rather than rebuilt, but the skill made the agent lead with the exact known root cause and its precise structural fix instead of a diffuse list of guesses. Co-Authored-By: Claude via Dash Claude-Session: https://claude.ai/code/session_01SYvwyQEa9xsKzsQTwpBuhp --- agentbase-browser/skills/ret-et-flow/SKILL.md | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 agentbase-browser/skills/ret-et-flow/SKILL.md diff --git a/agentbase-browser/skills/ret-et-flow/SKILL.md b/agentbase-browser/skills/ret-et-flow/SKILL.md new file mode 100644 index 0000000..f36f0e0 --- /dev/null +++ b/agentbase-browser/skills/ret-et-flow/SKILL.md @@ -0,0 +1,49 @@ +--- +name: ret-et-flow +description: Diagnosticerer og retter et eksisterende AgentBase-flow, der giver forkert, tomt eller fejlende output. Brug når brugeren siger "mit flow virker ikke", "det giver et forkert/tomt svar", "der kommer en fejl", "outputtet er tomt", eller vil fejlfinde/debugge/rette en agent, de allerede har bygget. Kræver at AgentBase-værktøjerne er tilsluttet. +--- + +# Ret et flow + +Når et flow giver et forkert eller tomt svar, så **byg det ikke om fra bunden.** +Reproducér fejlen på et rigtigt input, find den præcise byggeklods der fejler, +lav den *mindste* rettelse, og kør igen. Brugeren ser ikke lærredet (det er i en +anden fane), så vis det rigtige output i chatten undervejs. + +## Fejlfindingsløkken + +1. **Reproducér på et rigtigt input.** Kør flowet på præcis det input, der driller, + og se det *faktiske* output — ikke det, du regner med, det giver. Har du ikke et + input, der fejler, så bed brugeren om et. +2. **Find fejlen.** Læs kørslen med `get_execution` og find den byggeklods og det + håndtag (`node:handle`), der producerede forkert, tomt eller fejlet output. Gå + baglæns fra symptomet — den første node, der er gal, er årsagen; resten er følger. +3. **Lav den mindste ændring.** Ret kun det. Bekræft håndtagene med `get_node_type`, + og skriv grafen med `set_flow`. Udvid ikke flowet ud over dets formål. +4. **Kør igen på samme input.** Bekræft, at rettelsen virker. Gentag, til det er + pålideligt — stop ikke, bare fordi det er gemt. + +## Almindelige årsager — tjek disse først + +| Symptom | Årsag | Rettelse | +|---|---|---| +| Tomt svar / "Intet indhold angivet" efter en Hvis/ellers | Grenen er tom — `config` mangler `true_output`/`false_output` | Sæt begge i `config`'en, og før både sand- og falsk-grenen videre til næste trin | +| Rå `{pladsholder}` i output | Flere betingede grene samlet i én skabelon med flere variabler — kun den aktive gren udfyldes | Lad *hver* gren skrive den færdige tekst, og før dem til ÉT fælles felt (samme input-håndtag) | +| Fejl om filtype / "dataurl" vs. tekst | En fil er sendt direkte til et tekst-input | Sæt Dokument-OCR imellem — **aldrig** en kode-byggeklods (`python-code`) som type-oversætter | +| Kun første element behandlet / liste-fejl | En hel liste er sendt til en byggeklods, der forventer ét element | Pak behandlingen ind mellem Løkke Start og Løkke Slut | +| Løkke-styring virker ikke | Løkke Afbryd/Spring over ligger uden for løkken | Flyt dem ind på stien mellem Løkke Start og Løkke Slut | +| Sprogmodel giver fri tekst, hvor et system skal bruge faste felter | Manglende `response_schema` | Sæt et `response_schema` på Sprogmodel-byggeklodsen | + +Er årsagen ikke i tabellen, så lad `get_execution` pege på den — den viser hvert +trins input og output. `guide://flow-building` har den fulde `config`-form for +Hvis/ellers og type-reglerne. + +## Holdepunkter i chatten + +Vis brugeren det reproducerede, forkerte output og — efter rettelsen — det rette +output. De kan ikke se lærredet, så chatten er deres eneste indblik. Nævn åbent, +hvad du ændrede, og hvorfor. + +## Sprog + +Skriv alt, brugeren ser, på **dansk**. Node-id'er kan være korte ASCII. From ce49b349af7d7142742da58379d5cc0d934e0507 Mon Sep 17 00:00:00 2001 From: simo787c <92300326+simo787c@users.noreply.github.com> Date: Mon, 27 Jul 2026 11:01:10 +0200 Subject: [PATCH 3/3] ci(browser): add MCP connection drift-check workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Guards the two rot-prone facts the browser packs depend on — the MCP endpoint host and its OAuth auth model. Real drift here is ~1 event/year, always silent and total: the server moves or changes auth under a still repo and every packaged connector URL / skill instruction breaks at once. - scripts/check-mcp-drift.sh — fetches the live RFC 9728 metadata at api.agentbase.dk/.well-known/oauth-protected-resource/mcp and asserts: host reachable + HTTP 200; advertised `resource` equals the canonical https://api.agentbase.dk/mcp the packs ship; OAuth still advertised (authorization_servers non-empty); the canonical URL is actually present in a manifest/skill; and no plugin.json points at the dead host or carries a static-token block (userConfig/headers/Authorization/Bearer). The stale-host and token checks are scoped to plugin.json — skill prose may legitimately name the dead host as forbidden, so a repo-wide scan would false-positive. - .github/workflows/mcp-drift-check.yml — runs on pull_request, a weekly cron, and workflow_dispatch. On a non-PR failure it opens (or comments on an existing) "MCP connection drift detected" issue, because the failure that actually happens — the server moving under a still repo — surfaces only in the cron run, where a red check alone goes unseen. - .gitattributes — pin *.sh / *.yml to LF so CRLF can't break bash on the runner. Verified: live endpoint returns resource=https://api.agentbase.dk/mcp with one authorization server; script passes syntax + repo-scan checks against the current tree. Co-Authored-By: Claude via Dash Claude-Session: https://claude.ai/code/session_01SYvwyQEa9xsKzsQTwpBuhp --- .gitattributes | 4 ++ .github/workflows/mcp-drift-check.yml | 50 +++++++++++++++++++ scripts/check-mcp-drift.sh | 72 +++++++++++++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 .gitattributes create mode 100644 .github/workflows/mcp-drift-check.yml create mode 100755 scripts/check-mcp-drift.sh diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..a2e3ce0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +# Shell scripts and CI workflows must stay LF — CRLF breaks bash on Linux runners. +*.sh text eol=lf +*.yml text eol=lf +*.yaml text eol=lf diff --git a/.github/workflows/mcp-drift-check.yml b/.github/workflows/mcp-drift-check.yml new file mode 100644 index 0000000..b84aeac --- /dev/null +++ b/.github/workflows/mcp-drift-check.yml @@ -0,0 +1,50 @@ +name: MCP connection drift check + +# Verifies the live AgentBase MCP still matches what the packs ship (endpoint +# host + OAuth auth model). The failure this exists for is the server moving +# under a still repo — caught by the weekly cron, where a red check alone would +# go unseen, so a scheduled/dispatch failure also opens (or comments on) an issue. + +on: + pull_request: + schedule: + - cron: "17 6 * * 1" # Mondays 06:17 UTC + workflow_dispatch: + +permissions: + contents: read + issues: write + +jobs: + drift: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Check MCP connection contract + run: bash scripts/check-mcp-drift.sh + + - name: Open an issue on drift + # On a PR the failing check is visible to the author; a cron/dispatch run + # has no PR, so surface it as an issue instead of a silent red check. + if: failure() && github.event_name != 'pull_request' + env: + GH_TOKEN: ${{ github.token }} + RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + run: | + title="MCP connection drift detected" + body=$(printf '%s\n' \ + "The scheduled MCP drift check failed." \ + "" \ + "The AgentBase MCP connection contract no longer matches what the plugins ship — the endpoint host moved, OAuth is no longer advertised, or a manifest regressed to a static-token auth model." \ + "" \ + "Failing run: $RUN_URL" \ + "" \ + "Fix: update the canonical URL / auth model in the manifests and skills (and scripts/check-mcp-drift.sh) to match the live server, then re-run this workflow.") + existing=$(gh issue list --state open --search "in:title \"$title\"" --json number --jq '.[0].number // empty') + if [ -n "$existing" ]; then + gh issue comment "$existing" --body "$body" + else + gh issue create --title "$title" --body "$body" --label drift \ + || gh issue create --title "$title" --body "$body" + fi diff --git a/scripts/check-mcp-drift.sh b/scripts/check-mcp-drift.sh new file mode 100755 index 0000000..d602216 --- /dev/null +++ b/scripts/check-mcp-drift.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +# +# Guards the two rot-prone facts the AgentBase browser packs depend on: the MCP +# endpoint host and its OAuth auth model. Real drift here is rare (~1 event/year) +# but silent and total — the server moves or changes auth under a still repo, and +# every packaged connector URL / skill instruction breaks at once. This asserts +# the live server still matches what the manifests and skills ship, and that the +# manifests haven't regressed to a static-token auth model. +# +# Exits non-zero with a "DRIFT: ..." line on any mismatch. Needs curl + jq. +set -euo pipefail + +# The single canonical MCP URL the manifests and skills quote. If the server +# moves, this constant and the shipped strings must both change together. +CANONICAL_URL="https://api.agentbase.dk/mcp" +# RFC 9728 Protected Resource Metadata for /mcp — root-mounted, unauthenticated. +WELL_KNOWN="https://api.agentbase.dk/.well-known/oauth-protected-resource/mcp" +# Dead host from an earlier era; must never reappear in the repo. +STALE_HOST="api.flows.syv.ai" + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +PRM="$(mktemp)" +trap 'rm -f "$PRM"' EXIT + +fail() { echo "DRIFT: $*" >&2; exit 1; } + +echo "→ Fetching $WELL_KNOWN" +http_code="$(curl -sS -m 25 -o "$PRM" -w '%{http_code}' "$WELL_KNOWN")" \ + || fail "could not reach $WELL_KNOWN — host down, moved, or DNS gone" +[ "$http_code" = "200" ] || fail "well-known returned HTTP $http_code (expected 200)" +jq -e . "$PRM" >/dev/null 2>&1 || fail "well-known response is not valid JSON" + +# The server must still advertise /mcp at exactly the URL we ship. +resource="$(jq -r '.resource // empty' "$PRM")" +[ "$resource" = "$CANONICAL_URL" ] \ + || fail "advertised resource '$resource' != expected '$CANONICAL_URL' — endpoint moved" + +# OAuth must still be the auth model (RFC 9728 lists the authorization server(s)). +authz_count="$(jq '(.authorization_servers // []) | length' "$PRM")" +[ "$authz_count" -ge 1 ] \ + || fail "no authorization_servers advertised — OAuth no longer offered at $CANONICAL_URL" + +# The canonical URL must actually be what the repo ships (catches a stale constant +# above, or a manifest/skill that silently changed the URL). +grep -rqF "$CANONICAL_URL" "$REPO_ROOT" --include='*.json' --include='*.md' \ + --exclude-dir=.git \ + || fail "canonical URL $CANONICAL_URL is not present in any manifest or skill" + +# Per-manifest checks. The endpoint host and auth model can only really regress in +# a plugin.json — skill prose may legitimately NAME the dead host as forbidden, so +# scanning it repo-wide would false-positive. Two things a manifest must never do: +# 1. point at the dead host, or +# 2. carry a static-token auth block — OAuth is tokenless, so a userConfig prompt +# or an injected Authorization/headers block means we regressed to the old +# bearer-token model. (The server's own bearer_methods_supported is a normal +# OAuth field and is NOT checked here — only our manifests are.) +manifests=() +while IFS= read -r m; do manifests+=("$m"); done \ + < <(find "$REPO_ROOT" -path '*/.claude-plugin/plugin.json' -not -path '*/.git/*') +for m in "${manifests[@]}"; do + if grep -qF "$STALE_HOST" "$m"; then + fail "$m points at the dead host '$STALE_HOST' — use $CANONICAL_URL" + fi + if grep -qE '"(userConfig|headers|Authorization)"|Bearer ' "$m"; then + fail "$m carries a token-auth block (userConfig/headers/Authorization/Bearer) — should be OAuth-only" + fi +done + +echo "OK: MCP connection contract intact." +echo " resource = $resource" +echo " authorization_servers = $authz_count advertised" +echo " manifests checked = ${#manifests[@]} (no token-auth drift)"