@domesystems/templates 0.1.0

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.
Files changed (35) hide show
  1. package/README.md +168 -0
  2. package/ai-agent-for-documentation/.env.example +12 -0
  3. package/ai-agent-for-documentation/app/agent.yaml +31 -0
  4. package/ai-agent-for-documentation/app/help.md +19 -0
  5. package/ai-agent-for-documentation/app/instructions.md +21 -0
  6. package/ai-agent-for-documentation/docker-compose.yml +18 -0
  7. package/ai-agent-for-documentation/dome.tf +146 -0
  8. package/ai-agent-for-documentation/rules/answerer.cedar +35 -0
  9. package/ai-agent-for-documentation/template.yaml +130 -0
  10. package/ai-agent-for-documentation/verification.json +7 -0
  11. package/ai-agent-for-notion/.env.example +19 -0
  12. package/ai-agent-for-notion/app/agent.yaml +32 -0
  13. package/ai-agent-for-notion/app/help.md +14 -0
  14. package/ai-agent-for-notion/app/instructions.md +16 -0
  15. package/ai-agent-for-notion/docker-compose.yml +18 -0
  16. package/ai-agent-for-notion/dome.tf +163 -0
  17. package/ai-agent-for-notion/guards/redact-ssn-from-pages.json +22 -0
  18. package/ai-agent-for-notion/rules/answerer.cedar +29 -0
  19. package/ai-agent-for-notion/template.yaml +142 -0
  20. package/ai-agent-for-notion/verification.json +7 -0
  21. package/ai-agent-for-release-notes/.env.example +15 -0
  22. package/ai-agent-for-release-notes/app/agent.yaml +36 -0
  23. package/ai-agent-for-release-notes/app/help.md +20 -0
  24. package/ai-agent-for-release-notes/app/instructions.md +19 -0
  25. package/ai-agent-for-release-notes/docker-compose.yml +18 -0
  26. package/ai-agent-for-release-notes/dome.tf +165 -0
  27. package/ai-agent-for-release-notes/guards/block-leaked-keys.json +38 -0
  28. package/ai-agent-for-release-notes/rules/release-notes.cedar +49 -0
  29. package/ai-agent-for-release-notes/template.yaml +155 -0
  30. package/bin/dome-templates.mjs +5 -0
  31. package/package.json +29 -0
  32. package/src/cli.mjs +118 -0
  33. package/src/manifest.mjs +22 -0
  34. package/src/runtime.mjs +22 -0
  35. package/src/template-files.mjs +28 -0
package/README.md ADDED
@@ -0,0 +1,168 @@
1
+ # Dome templates
2
+
3
+ Reusable, importable governed-agent templates. Each template combines an HCL
4
+ configuration bundle for Dome with an optional companion application.
5
+
6
+ ## Use the template CLI
7
+
8
+ The public package is also an executable. It copies the template, creates a
9
+ local `.env` from `.env.example`, and generates the Compose file from the
10
+ runtime declaration in `template.yaml` — individual templates do not need a
11
+ Dockerfile or a committed Compose file.
12
+
13
+ ```bash
14
+ # Create a working copy in ./ai-agent-for-documentation.
15
+ npx @domesystems/templates init ai-agent-for-documentation
16
+
17
+ # Initialize when needed, provision Dome, then start the selected runtime.
18
+ npx @domesystems/templates up ai-agent-for-documentation
19
+ ```
20
+
21
+ `up` runs `dome import dome.tf`, then `docker compose` with a generated,
22
+ Git-ignored `.dome-compose.yaml`. Use `--no-start` to provision without
23
+ starting a container, `--skip-provision` to start an already-provisioned
24
+ template, `--detach` for a background container, and `--dir <directory>` to
25
+ choose a local destination.
26
+
27
+ Runtime selection is explicit rather than guessed:
28
+
29
+ ```yaml
30
+ app:
31
+ runtime:
32
+ pattern: chat # chat or run
33
+ language: python # python or typescript
34
+ image_tag: "0.1.0" # optional; defaults to latest
35
+ ```
36
+
37
+ The CLI maps `language` and `pattern` to a shared, published runtime image.
38
+ For an unusual runtime, set `app.runtime.image` to a complete image reference
39
+ (including its tag) to override that mapping.
40
+ Add a template directory to the package's `files` list when publishing a new
41
+ template so the CLI can discover it.
42
+
43
+ ## Use a template
44
+
45
+ ```bash
46
+ git clone https://github.com/dome-systems/templates.git
47
+ cd templates/<template>
48
+
49
+ brew install dome-systems/tap/dome
50
+ dome auth login
51
+ dome sandbox provision
52
+
53
+ # Preview resources, variables, and required permissions. Changes nothing.
54
+ dome import dome.tf --plan-only
55
+
56
+ # Apply after reviewing the preview. Dome prompts for required variables.
57
+ dome import dome.tf
58
+ ```
59
+
60
+ Imports run as asynchronous jobs in Dome. Existing resources are converged by
61
+ name, missing resources are created, and any destructive replacement is
62
+ refused. Secrets are input variables: they are never committed to a template
63
+ or returned in an export.
64
+
65
+ Every built companion app needs the one-time agent token created by the import:
66
+
67
+ ```bash
68
+ dome import outputs <job-id>
69
+ cp .env.example .env
70
+ docker compose up
71
+ ```
72
+
73
+ Tool and model credentials remain in Dome; the app only holds its agent token.
74
+
75
+ ### Runtime image
76
+
77
+ Templates do not build a runtime themselves. In development, clone the sibling
78
+ `dome-systems/template-runtime` repository and build the archetype image before
79
+ starting a template:
80
+
81
+ ```bash
82
+ cd template-runtime
83
+ docker build -f Dockerfile.chat -t ghcr.io/dome-systems/runtime-py-chat:dev .
84
+ docker build -f Dockerfile.run -t ghcr.io/dome-systems/runtime-py-run:dev .
85
+ ```
86
+
87
+ TypeScript equivalents are available as `ghcr.io/dome-systems/runtime-ts-chat`
88
+ and `ghcr.io/dome-systems/runtime-ts-run`; substitute either image in a template's Compose file
89
+ when using the Node runtime.
90
+
91
+ The CLI-generated Compose configuration uses the appropriate image and mounts
92
+ only the template's local `app/` configuration. Release templates should set a
93
+ versioned `app.runtime.image_tag` rather than relying on `latest`.
94
+
95
+ ## Runtime contract
96
+
97
+ Every built companion app follows the same small operational contract:
98
+
99
+ | Surface | Guarantee |
100
+ |---|---|
101
+ | `.env.example` | The complete committed list of values a local operator may need. It contains names and setup guidance, never real values. |
102
+ | `docker-compose.yml` | Starts the app on port `3000`, loads `.env`, mounts `app/` read-only, and declares the health check. |
103
+ | `GET /health` | Liveness only: returns `200 {"status":"ok"}` without calling Dome or an upstream system. Offline mode is valid. `/healthz` is an equivalent compatibility alias. |
104
+ | `GET /readyz` | Readiness of the initialized runtime API. Returns `200`; its `mode` is `live` or `offline`. |
105
+ | Docker `HEALTHCHECK` | Probes `/health`; inherited by every shared runtime image and repeated in Compose for a visible local contract. |
106
+
107
+ The Library renders each template's committed `.env.example` verbatim, so setup
108
+ requirements have one source of truth. Add a new variable there when the
109
+ companion app needs it; use `app.options.env` in `template.yaml` as well when
110
+ that value is interpolated into an agent prompt, starter, or help text.
111
+
112
+ ## Archetype containers
113
+
114
+ The separate `dome-systems/template-runtime` repository builds one image per app
115
+ shape. They contain no template-specific code — a template mounts an
116
+ `app/agent.yaml` giving its **prompt**, its **skills** and its **invoker**, which
117
+ is the shape the Dome agent runtime will take, so swapping a container for the
118
+ real runner is a config move rather than a rewrite.
119
+
120
+ Four UIs cover all 249 templates. A report is a run whose output is a table; an approval
121
+ console is a queue with two extra buttons.
122
+
123
+ | Archetype | Covers | Shapes | State |
124
+ |---|---|---|---|
125
+ | `ghcr.io/dome-systems/runtime-py-chat` | 66 | interactive-assistant | Built |
126
+ | `ghcr.io/dome-systems/runtime-py-run` | 120 | scheduled-job, report-dashboard | Built |
127
+ | `dome/template-queue` | 48 | triage-queue, approval-console | Not built |
128
+ | `dome/template-console` | 15 | external-service, developer-harness | Not built |
129
+
130
+ The governance drawer is shared chrome across all four, not a per-archetype feature.
131
+
132
+ Tools go through the Gateway over MCP; models go through the Broker's
133
+ Anthropic-compatible ingress. Both authenticate with the same agent token, which is why
134
+ the container holds one secret and no provider key. Without `DOME_TOKEN` it starts in
135
+ offline mode: the chrome works and the allow-list is still enforced, but tools and model
136
+ are simulated.
137
+
138
+ ## What is source and what is generated
139
+
140
+ `dome.tf` is the configuration source of truth for Dome resources. It is a
141
+ portable HCL bundle that `dome import` can inspect, preview, and apply.
142
+ `template.yaml` is catalog metadata and the source of truth for choosing the
143
+ shared local runtime; `rules/*.cedar` and `app/instructions.md` are
144
+ human-authored source.
145
+
146
+ ## Relationship to the Template Library
147
+
148
+ This repository is the Library's only template-content source. A merge to `main`
149
+ dispatches its commit SHA to `dome-systems/web-library`; that repository checks out
150
+ and builds the exact revision, then opens or updates one source-refresh PR. The
151
+ Library does not copy or edit template content, and a refresh PR must be merged
152
+ before the new source can be published.
153
+
154
+ The dispatch uses the `LIBRARY_SOURCE_SYNC_TOKEN` repository secret. It needs a
155
+ fine-grained token that may dispatch workflows in `dome-systems/web-library`.
156
+
157
+ ## Validation
158
+
159
+ Run the metadata and source-reference checks locally:
160
+
161
+ ```bash
162
+ npm install
163
+ npm run validate
164
+ terraform fmt -check -recursive
165
+ ```
166
+
167
+ CI runs the same checks. A plan-only import against a designated Dome sandbox can
168
+ be added when CI has an appropriate non-production workspace and credentials.
@@ -0,0 +1,12 @@
1
+ # The container holds exactly one secret.
2
+ #
3
+ # Tool credentials went into Dome when dome import ran and live behind the gateway.
4
+ # The provider key lives with the Broker. Neither is here, and neither should be.
5
+
6
+ # Revealed once after import: dome import outputs <job-id>
7
+ DOME_TOKEN=
8
+
9
+ # The gateway ROOT — not a bare host, and not the /mcp path.
10
+ # Copy the "Gateway URL" from the command above. The container derives
11
+ # /mcp for tools and /v1/messages for models from it.
12
+ DOME_GATEWAY_URL=
@@ -0,0 +1,31 @@
1
+ name: docs-answerer
2
+ title: Ask questions about product documentation
3
+ summary: "A chat agent that answers questions from the Dome Platform documentation.\
4
+ \ Nothing to set up upstream \u2014 the documentation MCP server takes no credential,\
5
+ \ so this reaches a real system on the first run. The connection carries three tools.\
6
+ \ Two answer questions. The third returns the whole documentation index, and the\
7
+ \ agent will reach for it \u2014 Dome refuses, and names the rule that refused it."
8
+ shape: interactive-assistant
9
+ prompt_file: instructions.md
10
+ help_file: help.md
11
+ model: claude-haiku-4-5-20251001
12
+ pool: docs-pool
13
+ max_tokens: 4096
14
+ skills:
15
+ - name: answer-from-documentation
16
+ description: Search the documentation, read the most relevant pages, answer from
17
+ them.
18
+ tools:
19
+ - domedocs/search
20
+ - domedocs/get_page
21
+ - domedocs/list_pages
22
+ invoker:
23
+ kind: chat
24
+ options:
25
+ identity:
26
+ mode: none
27
+ model:
28
+ provider: anthropic
29
+ model: claude-haiku-4-5-20251001
30
+ forbidden:
31
+ - domedocs/list_pages
@@ -0,0 +1,19 @@
1
+ Ask a question about the Dome Platform in plain language. The agent searches the
2
+ public documentation at `docs.domesystems.ai`, reads the pages it finds, and
3
+ answers from them.
4
+
5
+ **Nothing to set up upstream.** The documentation MCP server takes no
6
+ credential, so this template reaches a real system on its first run. The only
7
+ key the workspace needs is a model provider key — every template needs one —
8
+ and it goes to Dome, not into this container.
9
+
10
+ **Ask something broad.** "What is Dome" or "what does the gateway do". The agent
11
+ will reach for the documentation index to orient itself, that call will come
12
+ back refused, and you will watch it fall back to search and answer anyway. The
13
+ refusal is the rule, not the prompt.
14
+
15
+ **Show detail** in the header opens the design: the topology, which tools are
16
+ permitted, and the instructions the model was given.
17
+
18
+ Nothing here is the record. Every call, allowed or refused, is in the audit log
19
+ in Dome.
@@ -0,0 +1,21 @@
1
+ You answer questions about the Dome Platform from its documentation.
2
+
3
+ Work like this:
4
+
5
+ 1. If the question is broad — "what is Dome", "how does authorization work" —
6
+ start from the documentation index to see what exists.
7
+ 2. Search the documentation for the terms in the question. Search results carry
8
+ the path of every page they match.
9
+ 3. Read pages rather than searching repeatedly. Two or three searches is
10
+ plenty; after that, open the most promising pages in full **using the paths
11
+ the search results gave you**. Do not invent a path and try it.
12
+ 4. Answer from what you read, and name the pages you used.
13
+
14
+ If the documentation does not contain the answer, say so plainly. Do not fill
15
+ the gap from general knowledge — a confident answer that is not in the
16
+ documentation is worse than no answer, because the reader cannot tell the
17
+ difference.
18
+
19
+ Use whatever tools you have been given, and do not decline a request on the
20
+ assumption that you lack permission. If a call comes back refused, say what came
21
+ back and carry on with the tools that do work.
@@ -0,0 +1,18 @@
1
+ #
2
+ # Without DOME_TOKEN this starts in offline mode: the chrome works and the
3
+ # allow-list is still enforced, but tools and model are simulated.
4
+ services:
5
+ app:
6
+ # Built and published by dome-systems/template-runtime.
7
+ image: ghcr.io/dome-systems/runtime-py-chat:dev
8
+ env_file: .env
9
+ volumes:
10
+ - ./app:/config:ro
11
+ ports:
12
+ - "3000:3000"
13
+ healthcheck:
14
+ test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:3000/health', timeout=2)"]
15
+ interval: 30s
16
+ timeout: 3s
17
+ start_period: 10s
18
+ retries: 3
@@ -0,0 +1,146 @@
1
+ terraform {
2
+ required_providers {
3
+ dome = { source = "dome-systems/dome", version = ">= 0.1.0" }
4
+ }
5
+ }
6
+
7
+ variable "workspace_id" { type = string }
8
+ variable "anthropic_api_key" {
9
+ type = string
10
+ sensitive = true
11
+ }
12
+
13
+ resource "dome_gateway" "docs" {
14
+ workspace_id = var.workspace_id
15
+ name = "docs"
16
+ description = "Read surface over the public Dome Platform documentation"
17
+ is_default = true
18
+ }
19
+
20
+ resource "dome_mcp_connection" "domedocs" {
21
+ workspace_id = var.workspace_id
22
+ name = "domedocs"
23
+ protocol = "streamable-http"
24
+ url = "https://docs.domesystems.ai/mcp"
25
+ auth_method = "none"
26
+ }
27
+
28
+ resource "dome_llm_connection" "haiku" {
29
+ workspace_id = var.workspace_id
30
+ name = "haiku"
31
+ provider_id = "anthropic"
32
+ provider_config = jsonencode({ model = "claude-haiku-4-5-20251001" })
33
+ auth_method = "api-key"
34
+ credential_type = "shared"
35
+ managed_header_name = "x-api-key"
36
+ secret_values = { "x-api-key" = var.anthropic_api_key }
37
+ }
38
+
39
+ resource "dome_llm_pool" "docs" {
40
+ workspace_id = var.workspace_id
41
+ name = "docs-pool"
42
+ is_default = true
43
+ }
44
+
45
+ resource "dome_llm_pool_member" "haiku" {
46
+ workspace_id = var.workspace_id
47
+ pool = dome_llm_pool.docs.name
48
+ llm_connection = dome_llm_connection.haiku.name
49
+ }
50
+
51
+ resource "dome_gateway_llm_pool" "docs" {
52
+ workspace_id = var.workspace_id
53
+ gateway = dome_gateway.docs.name
54
+ llm_pool = dome_llm_pool.docs.name
55
+ }
56
+
57
+ resource "dome_gateway_tool" "search" {
58
+ workspace_id = var.workspace_id
59
+ gateway = dome_gateway.docs.name
60
+ mcp_connection = dome_mcp_connection.domedocs.name
61
+ tool = "search"
62
+ }
63
+
64
+ resource "dome_gateway_tool" "get_page" {
65
+ workspace_id = var.workspace_id
66
+ gateway = dome_gateway.docs.name
67
+ mcp_connection = dome_mcp_connection.domedocs.name
68
+ tool = "get_page"
69
+ }
70
+
71
+ resource "dome_gateway_tool" "list_pages" {
72
+ workspace_id = var.workspace_id
73
+ gateway = dome_gateway.docs.name
74
+ mcp_connection = dome_mcp_connection.domedocs.name
75
+ tool = "list_pages"
76
+ }
77
+
78
+ resource "dome_agent" "docs_answerer" {
79
+ workspace_id = var.workspace_id
80
+ name = "docs-answerer"
81
+ allowed_gateways = [dome_gateway.docs.name]
82
+ }
83
+
84
+ resource "dome_agent_rules_bundle" "docs_answerer" {
85
+ workspace_id = var.workspace_id
86
+ agent = dome_agent.docs_answerer.name
87
+ files = {
88
+ "answerer.cedar" = <<-EOT
89
+ permit ( principal, action == Dome::Action::"mcp:discover", resource );
90
+ permit ( principal, action == Dome::Action::"mcp:call", resource == Dome::MCPTool::"domedocs/search" );
91
+ permit ( principal, action == Dome::Action::"mcp:call", resource == Dome::MCPTool::"domedocs/get_page" );
92
+ forbid ( principal, action == Dome::Action::"mcp:call", resource == Dome::MCPTool::"domedocs/list_pages" );
93
+ EOT
94
+ }
95
+ }
96
+
97
+ resource "dome_filter" "keep_ssn_out_of_prompts" {
98
+ workspace_id = var.workspace_id
99
+ name = "keep-ssn-out-of-prompts"
100
+ description = "Redact US SSN patterns out of anything sent to the provider"
101
+ config = jsonencode({
102
+ text = { components = [{ action = "FILTER_ACTION_REDACT", matchers = [{ ssn = {} }] }] }
103
+ })
104
+ }
105
+
106
+ resource "dome_llm_connection_filters" "haiku_requests" {
107
+ workspace_id = var.workspace_id
108
+ llm_connection = dome_llm_connection.haiku.name
109
+ direction = "request"
110
+ filters = [dome_filter.keep_ssn_out_of_prompts.name]
111
+ }
112
+
113
+ resource "dome_quota" "agent_daily_spend" {
114
+ workspace_id = var.workspace_id
115
+ dimension = "llm"
116
+ unit = "dome_usd"
117
+ subject_type = "agent"
118
+ subject = dome_agent.docs_answerer.name
119
+ scope = "total"
120
+ window = "daily"
121
+ limit_amount = 5000000
122
+ name = "docs-answerer daily spend"
123
+ }
124
+
125
+ resource "dome_quota" "search_calls" {
126
+ workspace_id = var.workspace_id
127
+ dimension = "tool"
128
+ unit = "calls"
129
+ subject_type = "tool_connection"
130
+ subject = dome_mcp_connection.domedocs.name
131
+ scope = "total"
132
+ window = "daily"
133
+ limit_amount = 500
134
+ name = "domedocs search calls"
135
+ }
136
+
137
+ resource "dome_agent_key" "runtime" {
138
+ workspace_id = var.workspace_id
139
+ agent = dome_agent.docs_answerer.name
140
+ name = "runtime"
141
+ }
142
+
143
+ output "docs_answerer_token" {
144
+ value = dome_agent_key.runtime.token
145
+ sensitive = true
146
+ }
@@ -0,0 +1,35 @@
1
+ // answer-from-dome-docs — authorization rules
2
+ //
3
+ // The documentation MCP server is read-only upstream: there is no write tool to
4
+ // forbid here, so the boundary this template demonstrates is the allow-list
5
+ // itself. `search` and `get_page` are what answering a question needs.
6
+ // `list_pages` returns the entire documentation index — the call an agent makes
7
+ // to enumerate a corpus rather than to answer about it — so it is on the
8
+ // gateway, visible to the model, and denied.
9
+ //
10
+ // The write-boundary version of this story is
11
+ // ai-agent-for-notion, where a Notion page-creation tool is
12
+ // reachable and refused.
13
+
14
+ permit ( principal, action == Dome::Action::"mcp:discover", resource );
15
+
16
+ permit (
17
+ principal,
18
+ action == Dome::Action::"mcp:call",
19
+ resource == Dome::MCPTool::"domedocs/search"
20
+ );
21
+
22
+ permit (
23
+ principal,
24
+ action == Dome::Action::"mcp:call",
25
+ resource == Dome::MCPTool::"domedocs/get_page"
26
+ );
27
+
28
+ // Registering an agent against a gateway auto-generates an Agent Form policy
29
+ // permitting any tool whose `gateways` attribute contains that gateway. A
30
+ // permit cannot narrow that; only a forbid can. Cedar forbid always wins.
31
+ forbid (
32
+ principal,
33
+ action == Dome::Action::"mcp:call",
34
+ resource == Dome::MCPTool::"domedocs/list_pages"
35
+ );
@@ -0,0 +1,130 @@
1
+ apiVersion: templates.domesystems.ai/v1
2
+ kind: Template
3
+
4
+ metadata:
5
+ name: answer-from-dome-docs
6
+ slug: ai-agent-for-documentation
7
+ title: Ask questions about product documentation
8
+ target_query: ai chatbot for documentation
9
+ summary: >-
10
+ A chat agent that answers questions from the Dome Platform documentation.
11
+ Nothing to set up upstream — the documentation MCP server takes no
12
+ credential, so this reaches a real system on the first run. The connection
13
+ carries three tools. Two answer questions. The third returns the whole
14
+ documentation index, and the agent will reach for it — Dome refuses, and
15
+ names the rule that refused it.
16
+ domain: productivity
17
+ shape: interactive-assistant
18
+ ui: chat
19
+ business_pattern: consumes
20
+ governance_interest: [read-only, tool-scoped-access]
21
+
22
+ # Library-only topology and documentation data. `dome.tf` is the deployable source.
23
+ catalog:
24
+ gateway:
25
+ name: docs
26
+ description: Read surface over the public Dome Platform documentation
27
+ default: true
28
+
29
+ connections:
30
+ - name: domedocs
31
+ protocol: streamable-http
32
+ url: https://docs.domesystems.ai/mcp
33
+ # The whole point of this template. A public MCP server, no token, no
34
+ # consent screen, no account to create upstream.
35
+ auth:
36
+ method: none
37
+ permit:
38
+ - search
39
+ - get_page
40
+ # On the gateway on purpose, so the model can see it and try. Cedar
41
+ # forbids it, and a forbid beats the auto-generated Agent Form permit.
42
+ # Without this there is no denial to observe.
43
+ forbid:
44
+ - list_pages
45
+
46
+ model:
47
+ name: haiku
48
+ provider: anthropic
49
+ model_id: claude-haiku-4-5-20251001
50
+ secret:
51
+ env: ANTHROPIC_API_KEY
52
+ variable: anthropic_api_key
53
+ label: an Anthropic API key
54
+
55
+ pool:
56
+ name: docs-pool
57
+ default: true
58
+
59
+ agent:
60
+ name: docs-answerer
61
+ # No identity. This template's governance story is the allow-list, and
62
+ # act-as would add a second secret to the one thing in the library that
63
+ # needs none. The caller-scoped story is answer-from-knowledge-base.
64
+ act_as:
65
+ method: none
66
+
67
+ rules:
68
+ file: rules/answerer.cedar
69
+
70
+ # A text filter on the *model* request. Whatever a person types into the box
71
+ # goes to a provider, and this is the cheapest true statement a template can
72
+ # make: an SSN never reaches Anthropic. Text-kind, so it binds to the model
73
+ # connection — a tool connection would refuse it.
74
+ guards:
75
+ filters:
76
+ - name: keep-ssn-out-of-prompts
77
+ description: Redact US SSN patterns out of anything sent to the provider
78
+ why: >-
79
+ Whatever a person types into the box goes to a provider. This is the
80
+ cheapest true thing a template can claim — an SSN never reaches
81
+ Anthropic — and it costs one line because the credential and the
82
+ routing already live in Dome. Text-kind, so it binds to the model
83
+ connection; a tool connection refuses a text filter outright.
84
+ redact_ssn: true
85
+ bind: { model: haiku, direction: request }
86
+
87
+ quotas:
88
+ # What the agent may spend with Dome, per day.
89
+ - subject: agent
90
+ agent: docs-answerer
91
+ unit: dome_usd
92
+ limit: 5
93
+ window: daily
94
+ name: docs-answerer daily spend
95
+ # And a call ceiling on the one tool that does the work. The docs server is
96
+ # public and someone else pays for it, so not hammering it is part of using
97
+ # it politely — a rate limit with a reason, rather than a round number.
98
+ - subject: tool
99
+ tool: domedocs/search
100
+ unit: calls
101
+ limit: 500
102
+ window: daily
103
+ name: domedocs search calls
104
+
105
+ app:
106
+ runtime:
107
+ pattern: chat
108
+ language: python
109
+ agent:
110
+ prompt: app/instructions.md
111
+ help: app/help.md
112
+ model: claude-haiku-4-5-20251001
113
+ # 2048 truncates a documentation answer mid-sentence, and a truncated turn
114
+ # loses the tool call it was half-way through writing.
115
+ max_tokens: 4096
116
+ skills:
117
+ - name: answer-from-documentation
118
+ description: Search the documentation, read the most relevant pages, answer from them.
119
+ tools:
120
+ - domedocs/search
121
+ - domedocs/get_page
122
+ - domedocs/list_pages
123
+ invoker:
124
+ kind: chat
125
+ options:
126
+ identity:
127
+ mode: none
128
+ model:
129
+ provider: anthropic
130
+ model: claude-haiku-4-5-20251001
@@ -0,0 +1,7 @@
1
+ {
2
+ "verified": "2026-09-12T19:25:26Z",
3
+ "context": "api-domesystems-ai-dome-systems-core-dome-library",
4
+ "gateway": "docs",
5
+ "agent": "docs-answerer",
6
+ "cli": "1.0.2"
7
+ }
@@ -0,0 +1,19 @@
1
+ # The container holds exactly one secret.
2
+ #
3
+ # Tool credentials went into Dome when dome import ran and live behind the gateway.
4
+ # The provider key lives with the Broker. Neither is here, and neither should be.
5
+
6
+ # Revealed once after import: dome import outputs <job-id>
7
+ DOME_TOKEN=
8
+
9
+ # The gateway ROOT — not a bare host, and not the /mcp path.
10
+ # Copy the "Gateway URL" from the command above. The container derives
11
+ # /mcp for tools and /v1/messages for models from it.
12
+ DOME_GATEWAY_URL=
13
+
14
+ # The second secret, and the only one an identity-enabled blueprint adds.
15
+ # The container signs the act-as header with it; the gateway verifies the
16
+ # signature before it will believe who the request claims to be. Without
17
+ # that, anyone holding the agent token could claim to be anyone.
18
+ # Must match the actas_hmac_secret supplied to dome import.
19
+ ACTAS_HMAC_SECRET=
@@ -0,0 +1,32 @@
1
+ name: knowledge-answerer
2
+ title: Ask questions across your Notion workspace
3
+ summary: "A chat agent that answers questions from your Notion workspace. The connection\
4
+ \ carries 43 tools, twenty-odd of which write. Two are permitted. Ask it to create\
5
+ \ a page and it will try \u2014 and Dome will refuse, naming the rule that refused\
6
+ \ it."
7
+ shape: interactive-assistant
8
+ prompt_file: instructions.md
9
+ help_file: help.md
10
+ model: claude-sonnet-5
11
+ pool: answerer-pool
12
+ max_tokens: 2048
13
+ skills:
14
+ - name: answer-from-notion
15
+ description: Search the workspace, read the most relevant pages, answer from them.
16
+ tools:
17
+ - notion/notion-search
18
+ - notion/notion-fetch
19
+ - notion/notion-create-pages
20
+ invoker:
21
+ kind: chat
22
+ options:
23
+ identity:
24
+ mode: oidc-stub
25
+ personas:
26
+ - id: alice
27
+ - id: bob
28
+ model:
29
+ provider: anthropic
30
+ model: claude-sonnet-5
31
+ forbidden:
32
+ - notion/notion-create-pages
@@ -0,0 +1,14 @@
1
+ Ask a question in plain language. The agent searches the connected Notion
2
+ workspace, reads the pages it finds, and answers from them.
3
+
4
+ **Show detail** in the header opens the design: the topology, which tools are
5
+ permitted, and the instructions the model was given.
6
+
7
+ **Try changing who is asking.** Alice is permitted. Bob is not, and the same
8
+ question comes back refused — the difference is the rule, not the wording.
9
+
10
+ **Ask it to create a page.** It will try, and the attempt will be blocked. The
11
+ connection carries 43 Notion tools; two are permitted.
12
+
13
+ Nothing here is the record. Every call, allowed or refused, is in the audit log
14
+ in Dome.
@@ -0,0 +1,16 @@
1
+ You answer questions using the connected Notion workspace.
2
+
3
+ Work like this:
4
+
5
+ 1. Search Notion for pages relevant to the question.
6
+ 2. Fetch the most promising two or three and read them.
7
+ 3. Answer from what you found, and name the pages you used.
8
+
9
+ If the workspace does not contain the answer, say so plainly. Do not fill the
10
+ gap from general knowledge — a confident answer that is not in the
11
+ documentation is worse than no answer, because the reader cannot tell the
12
+ difference.
13
+
14
+ Use whatever tools you have been given, and do not decline a request on the
15
+ assumption that you lack permission. If an action is not allowed, attempting it
16
+ is how you and the person asking find that out; report what came back.