@reunionstudio/airlock-mcp 0.1.2 → 0.1.4
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.
- package/.agents/skills/airlock-mcp/SKILL.md +134 -14
- package/.agents/skills/airlock-mcp/agents/openai.yaml +2 -2
- package/README.md +93 -11
- package/docs/architecture.md +17 -6
- package/docs/install-surface.md +45 -5
- package/docs/spec-workbench-architecture.md +14 -3
- package/docs/spec-workspace.md +5 -0
- package/docs/workflows.md +127 -3
- package/package.json +1 -1
- package/patterns/manifest.json +6 -0
- package/patterns/okf-knowledge-bundle/README.md +64 -0
- package/patterns/okf-knowledge-bundle/sample.records.json +16 -0
- package/patterns/okf-knowledge-bundle/spec.config.json +64 -0
- package/setup.py +1 -1
- package/src/airlock_mcp/__init__.py +1 -1
- package/src/airlock_mcp/app_context.py +303 -0
- package/src/airlock_mcp/art.py +1 -1
- package/src/airlock_mcp/bootstrap.py +65 -4
- package/src/airlock_mcp/cli.py +32 -0
- package/src/airlock_mcp/summary.py +1 -0
- package/src/mcp.mjs +5 -5
- package/src/text.mjs +85 -16
- package/src/workbench.mjs +65 -2
|
@@ -16,8 +16,9 @@ This repo is an Airlock MCP workspace for drafting Airlock specs with Codex.
|
|
|
16
16
|
The public install surface is Airlock MCP, for example
|
|
17
17
|
`npx @reunionstudio/airlock-mcp install`. Airlock MCP is the single installed
|
|
18
18
|
interface for building specs, using specs, pulling and pushing governed data,
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
building apps or workflows that use existing specs, and discovering
|
|
20
|
+
improvements from real use cases. This project repo remains the durable memory
|
|
21
|
+
for the specs being drafted.
|
|
21
22
|
|
|
22
23
|
## Repo Naming
|
|
23
24
|
|
|
@@ -45,7 +46,13 @@ installed Airlock app.
|
|
|
45
46
|
## Starting A Spec Project
|
|
46
47
|
|
|
47
48
|
After bootstrap, welcome the user and orient before creating a workspace. Start
|
|
48
|
-
|
|
49
|
+
by asking which delivery mode they want:
|
|
50
|
+
|
|
51
|
+
1. Spec-first: design governed specs before building the app surface.
|
|
52
|
+
2. App-first: build from existing specs.
|
|
53
|
+
3. Co-development: develop the app and specs together.
|
|
54
|
+
|
|
55
|
+
For spec-first or co-development work, ask:
|
|
49
56
|
|
|
50
57
|
What process do you want to improve?
|
|
51
58
|
|
|
@@ -79,10 +86,64 @@ plan for more. Do not create the first workspace until the user chooses a path.
|
|
|
79
86
|
Create `posts` only when the user wants a shared feedback loop or explicitly
|
|
80
87
|
asks for the posts pattern.
|
|
81
88
|
|
|
89
|
+
## Building Apps With Existing Specs
|
|
90
|
+
|
|
91
|
+
Use this path when the user wants to build an app, dashboard, approval queue,
|
|
92
|
+
decision UI, analysis workflow, scheduled agent, or other code that uses specs
|
|
93
|
+
they already have access to. Treat this as app/workflow implementation, not
|
|
94
|
+
spec editing, unless the user explicitly asks to change specs.
|
|
95
|
+
|
|
96
|
+
Use `airlock-mcp init-app-context` in an app repo when the app needs local
|
|
97
|
+
Airlock context. It creates `airlock/specs.manifest.json`,
|
|
98
|
+
`airlock/spec-snapshots/`, `airlock/sample-records/`, and generated helper
|
|
99
|
+
folders. These files are app-local references, not canonical specs. Canonical
|
|
100
|
+
specs live in the specs repo or installed Airlock.
|
|
101
|
+
|
|
102
|
+
Identify:
|
|
103
|
+
|
|
104
|
+
- the app goal and decision the app should support
|
|
105
|
+
- read specs such as budgets, expenses, requests, forecasts, observations,
|
|
106
|
+
payouts, or reference data
|
|
107
|
+
- write specs such as decisions, approvals, comments, commitments, actions, or
|
|
108
|
+
follow-ups
|
|
109
|
+
- where the app should run, such as Streamlit, web app, CLI, notebook,
|
|
110
|
+
scheduled agent, or existing app framework
|
|
111
|
+
- the Airlock access path available in this environment
|
|
112
|
+
- identity, evidence, timestamp, approval, and separation-of-duties rules
|
|
113
|
+
|
|
114
|
+
Installed Airlock separates procedure intent:
|
|
115
|
+
|
|
116
|
+
- `observe.*`: read-only governance observation for discovery, health, access
|
|
117
|
+
explanation, governance maps, activity, billing events, and context packets.
|
|
118
|
+
- `agent.*`: governed agent work in the actor's scope.
|
|
119
|
+
- `admin.*`: administrative mutation and operational changes.
|
|
120
|
+
|
|
121
|
+
For app-first work, use observe payloads such as `observe.procedures`,
|
|
122
|
+
`observe.specs`, `observe.spec`, `observe.governance_map`,
|
|
123
|
+
`observe.explain_access`, `observe.health`, `observe.activity`,
|
|
124
|
+
`observe.admin_activity`, `observe.spec_admin_activity`, and
|
|
125
|
+
`observe.billing_events` before inventing custom read paths. For `alter_spec`
|
|
126
|
+
activity, use `CHANGED_SECTIONS` and `CHANGED_FIELDS` to triage what changed
|
|
127
|
+
before fetching version snapshots. Do not call retired admin read wrappers such as `admin.list_specs`, `admin.describe_role`,
|
|
128
|
+
or `admin.list_events`; use the matching observe list/detail procedure.
|
|
129
|
+
|
|
130
|
+
The app may orient the user with summaries, comparisons, rankings, exception
|
|
131
|
+
queues, proposals, or dashboards. It should submit governed choices back
|
|
132
|
+
through an Airlock spec contract. Do not write directly to Airlock-owned tables,
|
|
133
|
+
stages, generated views, or generated tables. Do not bypass spec workflow just
|
|
134
|
+
because the app can connect to Snowflake. If no suitable decision or action spec
|
|
135
|
+
exists, explain the gap and propose a small spec-design step.
|
|
136
|
+
|
|
137
|
+
In co-development mode, keep two tracks visible:
|
|
138
|
+
|
|
139
|
+
- Spec track: row grain, columns, samples, access, validation, workflow
|
|
140
|
+
- App track: screens, reads, decisions, writes, user actions, runtime
|
|
141
|
+
|
|
82
142
|
## Working Style
|
|
83
143
|
|
|
84
144
|
- Use the repo-scoped `$airlock-mcp` skill for spec drafting, review, and
|
|
85
|
-
pattern selection
|
|
145
|
+
pattern selection, or for app/workflow implementation that uses existing
|
|
146
|
+
Airlock specs.
|
|
86
147
|
- Keep drafts small and concrete. Prefer one useful governed output over a
|
|
87
148
|
large speculative process map, then keep a plan for later specs.
|
|
88
149
|
- Preserve decisions in workspace files so future Codex sessions can resume
|
package/src/airlock_mcp/cli.py
CHANGED
|
@@ -5,6 +5,7 @@ import sys
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
|
|
7
7
|
from . import __version__
|
|
8
|
+
from .app_context import APP_CONTEXT_MODES, format_app_context_result, init_app_context
|
|
8
9
|
from .art import about_text
|
|
9
10
|
from .bootstrap import bootstrap_repo, format_bootstrap_result
|
|
10
11
|
from .jsonio import read_json
|
|
@@ -64,6 +65,17 @@ def init_repo(args: argparse.Namespace) -> int:
|
|
|
64
65
|
return 0
|
|
65
66
|
|
|
66
67
|
|
|
68
|
+
def init_app(args: argparse.Namespace) -> int:
|
|
69
|
+
result = init_app_context(
|
|
70
|
+
Path(args.path),
|
|
71
|
+
mode=args.mode,
|
|
72
|
+
spec_sources=[Path(source) for source in args.spec],
|
|
73
|
+
force=args.force,
|
|
74
|
+
)
|
|
75
|
+
print(format_app_context_result(result))
|
|
76
|
+
return 0
|
|
77
|
+
|
|
78
|
+
|
|
67
79
|
def init_workspace(args: argparse.Namespace) -> int:
|
|
68
80
|
patterns = load_patterns(repo_root())
|
|
69
81
|
pattern = patterns[args.pattern]
|
|
@@ -308,6 +320,26 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
308
320
|
init_repo_parser.add_argument("--force", action="store_true", help="Overwrite AGENTS.md and the repo-scoped skill.")
|
|
309
321
|
init_repo_parser.set_defaults(func=init_repo)
|
|
310
322
|
|
|
323
|
+
init_app_parser = subparsers.add_parser(
|
|
324
|
+
"init-app-context",
|
|
325
|
+
help="Prepare an app repo airlock/ context with spec snapshots and a manifest.",
|
|
326
|
+
)
|
|
327
|
+
init_app_parser.add_argument("path", nargs="?", default=".", help="App repo path. Defaults to current directory.")
|
|
328
|
+
init_app_parser.add_argument(
|
|
329
|
+
"--mode",
|
|
330
|
+
choices=APP_CONTEXT_MODES,
|
|
331
|
+
default="app-first",
|
|
332
|
+
help="Development mode. Defaults to app-first.",
|
|
333
|
+
)
|
|
334
|
+
init_app_parser.add_argument(
|
|
335
|
+
"--spec",
|
|
336
|
+
action="append",
|
|
337
|
+
default=[],
|
|
338
|
+
help="Spec workspace directory or spec JSON file to snapshot. Repeat for multiple specs.",
|
|
339
|
+
)
|
|
340
|
+
init_app_parser.add_argument("--force", action="store_true", help="Overwrite app context files.")
|
|
341
|
+
init_app_parser.set_defaults(func=init_app)
|
|
342
|
+
|
|
311
343
|
init_parser = subparsers.add_parser("init", help="Create a spec workspace.")
|
|
312
344
|
init_parser.add_argument("name", help="Workspace folder name.")
|
|
313
345
|
init_parser.add_argument(
|
|
@@ -247,6 +247,7 @@ def workspace_summary(
|
|
|
247
247
|
f" owner_role: {_format_value(core.get('owner_role'))}",
|
|
248
248
|
f" published: {_format_value(core.get('is_published'))}",
|
|
249
249
|
f" archived: {_format_value(core.get('is_archived'))}",
|
|
250
|
+
f" payload_adapter: {_format_value(core.get('payload_adapter'), default='default')}",
|
|
250
251
|
f" description: {_truncate(core.get('description')) or 'none'}",
|
|
251
252
|
"",
|
|
252
253
|
"file_rules:",
|
package/src/mcp.mjs
CHANGED
|
@@ -7,7 +7,7 @@ const GETTING_STARTED_URI = "airlock://getting-started";
|
|
|
7
7
|
|
|
8
8
|
const START_TOOL = {
|
|
9
9
|
name: "airlock_start",
|
|
10
|
-
description: "Return Airlock MCP setup guidance for
|
|
10
|
+
description: "Return Airlock MCP setup guidance for specs and apps that use specs.",
|
|
11
11
|
inputSchema: {
|
|
12
12
|
type: "object",
|
|
13
13
|
properties: {
|
|
@@ -44,10 +44,10 @@ export function handleMcpRequest(message) {
|
|
|
44
44
|
},
|
|
45
45
|
serverInfo: {
|
|
46
46
|
name: "airlock",
|
|
47
|
-
version: "0.1.
|
|
47
|
+
version: "0.1.4",
|
|
48
48
|
},
|
|
49
49
|
instructions:
|
|
50
|
-
"Airlock MCP helps agents improve processes with Airlock specs. Use airlock_start for orientation or the airlock_* tools to bootstrap, draft, check, summarize, export, and render specs.",
|
|
50
|
+
"Airlock MCP helps agents improve processes with Airlock specs and build apps or workflows that use existing specs. Use airlock_start for orientation or the airlock_* tools to bootstrap, draft, check, summarize, export, and render specs.",
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
53
|
|
|
@@ -84,7 +84,7 @@ export function handleMcpRequest(message) {
|
|
|
84
84
|
{
|
|
85
85
|
name: "airlock-start",
|
|
86
86
|
title: "Start Airlock",
|
|
87
|
-
description: "Bootstrap a Git-backed specs repo
|
|
87
|
+
description: "Bootstrap a Git-backed specs repo or choose an Airlock app/spec path.",
|
|
88
88
|
arguments: [
|
|
89
89
|
{
|
|
90
90
|
name: "project",
|
|
@@ -103,7 +103,7 @@ export function handleMcpRequest(message) {
|
|
|
103
103
|
}
|
|
104
104
|
const project = params?.arguments?.project || "Home";
|
|
105
105
|
return makeResponse(id, {
|
|
106
|
-
description: "Start building
|
|
106
|
+
description: "Start building specs or apps that use Airlock specs.",
|
|
107
107
|
messages: [
|
|
108
108
|
{
|
|
109
109
|
role: "user",
|
package/src/text.mjs
CHANGED
|
@@ -25,19 +25,23 @@ Set up this project as an Airlock specs repo. If this project is not already a
|
|
|
25
25
|
Git repo, recommend storing it in version control, preferably GitHub if that is
|
|
26
26
|
available. If you are creating the repo for me, ask where the ${repoName}
|
|
27
27
|
directory should live before making it, then offer to initialize git and create
|
|
28
|
-
or push a GitHub repo.
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
or push a GitHub repo. If I am in an app repo and want to build software that
|
|
29
|
+
uses existing specs, or develop the app and specs together, do not bootstrap a
|
|
30
|
+
specs repo unless I ask for spec edits.
|
|
31
|
+
|
|
32
|
+
Welcome me by asking whether I want spec-first, app-first, or co-development:
|
|
33
|
+
spec-first designs governed specs before the app, app-first builds from existing
|
|
34
|
+
specs, and co-development evolves the app and specs together. For spec-first or
|
|
35
|
+
co-development, ask what process I want to improve. Explain that Airlock works
|
|
31
36
|
best when we can identify the loop around that process: what information comes
|
|
32
37
|
in, what context helps us understand it, what decision needs to be made, and
|
|
33
38
|
what action happens after the decision. Information may come from apps, files,
|
|
34
|
-
forms, people,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
redact secrets.
|
|
39
|
+
forms, people, emails, calls, mail, websites, APIs, data feeds, or physical
|
|
40
|
+
events. Actions may go back through those same places. Ask whether I already
|
|
41
|
+
have artifacts: CSV or Excel files, JSON samples, API docs, schemas, forms,
|
|
42
|
+
screenshots, PDFs, exports, message examples, or other content people already
|
|
43
|
+
use. Treat a small real sample as stronger evidence than a long explanation,
|
|
44
|
+
and remind me to redact secrets.
|
|
41
45
|
|
|
42
46
|
When useful, check the reusable airlock-specs library for starting points,
|
|
43
47
|
patterns, and ideas, but do not assume those library specs match current
|
|
@@ -45,7 +49,26 @@ third-party systems. Prefer current API docs, real exports, samples, and other
|
|
|
45
49
|
artifacts when they conflict with a library shape.
|
|
46
50
|
|
|
47
51
|
Ask for the messy version, then help turn it into a small first Airlock spec
|
|
48
|
-
and a plan for more. Do not create the first workspace until I choose a path
|
|
52
|
+
and a plan for more. Do not create the first workspace until I choose a path.
|
|
53
|
+
|
|
54
|
+
If I want app-first or co-development, ask for the app goal, the specs I can
|
|
55
|
+
access, which specs are read sources, which spec records decisions or actions,
|
|
56
|
+
and where the app should run. Teach the installed Airlock procedure split:
|
|
57
|
+
\`airlock.observe.*\` is read-only governance observation,
|
|
58
|
+
\`airlock.agent.*\` is governed agent work, and \`airlock.admin.*\` is
|
|
59
|
+
administrative mutation. Prefer observe payloads such as
|
|
60
|
+
\`observe.procedures\`, \`observe.specs\`, \`observe.spec\`,
|
|
61
|
+
\`observe.governance_map\`, \`observe.explain_access\`, \`observe.health\`,
|
|
62
|
+
\`observe.activity\`, \`observe.admin_activity\`, \`observe.spec_admin_activity\`,
|
|
63
|
+
and \`observe.billing_events\` before inventing custom read paths. For \`alter_spec\`
|
|
64
|
+
activity, use \`CHANGED_SECTIONS\` and \`CHANGED_FIELDS\` to triage what changed
|
|
65
|
+
before fetching version snapshots. Offer to run \`airlock-mcp init-app-context\`
|
|
66
|
+
in the app repo to seed \`airlock/specs.manifest.json\`, spec snapshots, sample records, and
|
|
67
|
+
generated helper folders. Help code the app using approved Airlock/Snowflake access paths.
|
|
68
|
+
Do not use retired admin read wrappers such as
|
|
69
|
+
\`admin.list_specs\`, \`admin.describe_role\`, or \`admin.list_events\`; use
|
|
70
|
+
the matching observe procedure. Do not write directly to Airlock-owned tables
|
|
71
|
+
or bypass spec workflow.`;
|
|
49
72
|
}
|
|
50
73
|
|
|
51
74
|
export function nextSteps(project) {
|
|
@@ -63,11 +86,16 @@ ${airlockPrompt(project)
|
|
|
63
86
|
|
|
64
87
|
Airlock MCP will offer:
|
|
65
88
|
- process discovery before choosing a spec pattern
|
|
89
|
+
- spec-first, app-first, and co-development planning
|
|
66
90
|
- spec design with the bundled workbench
|
|
67
91
|
- Airlock operating patterns for OODA loops and separation of duties
|
|
92
|
+
- read-only observe procedures for governance maps, health, access explanation, activity, billing events, and context packets
|
|
93
|
+
- app context seeding with spec snapshots and manifests
|
|
94
|
+
- app and workflow coding against existing Airlock specs
|
|
68
95
|
- observe specs for controlled interface ingestion
|
|
69
96
|
- orient specs for proposals, context, scoring, or exception queues
|
|
70
97
|
- decision specs and action specs for governed follow-through
|
|
98
|
+
- OKF-style Markdown knowledge bundles for accepted agent context
|
|
71
99
|
- artifact-grounded drafts from CSV, Excel, JSON, API docs, schemas, forms, screenshots, PDFs, or exports
|
|
72
100
|
- airlock-specs library patterns as starting points, checked against current artifacts`;
|
|
73
101
|
}
|
|
@@ -77,16 +105,23 @@ export function gettingStartedText(project) {
|
|
|
77
105
|
|
|
78
106
|
Airlock MCP is the single installed interface for AI agents working with
|
|
79
107
|
Airlock. It helps a person and their agent improve processes by designing
|
|
80
|
-
specs, using specs for governed data movement,
|
|
81
|
-
|
|
108
|
+
specs, using specs for governed data movement, planning OODA loops, and building
|
|
109
|
+
apps or workflows that read from and submit through existing specs.
|
|
82
110
|
|
|
83
|
-
Airlock MCP gives agents
|
|
111
|
+
Airlock MCP gives agents four kinds of Airlock help:
|
|
84
112
|
|
|
85
113
|
1. Spec design: draft, check, revise, import, clone, and prepare specs for
|
|
86
114
|
installed Airlock validation.
|
|
87
115
|
2. Airlock operating patterns: use specs to organize observations, orientation,
|
|
88
116
|
governed decisions, controlled actions, separation of duties, and feedback
|
|
89
117
|
loops.
|
|
118
|
+
3. App and workflow implementation: build dashboards, queues, decision UIs,
|
|
119
|
+
analyses, and agent workflows that use existing specs without bypassing
|
|
120
|
+
Airlock contracts.
|
|
121
|
+
4. Governance observation: use installed Airlock's read-only \`observe.*\`
|
|
122
|
+
procedures to inspect setup, access, activity, billing events, health,
|
|
123
|
+
context packets, and governance maps before deciding what an app or agent
|
|
124
|
+
should do.
|
|
90
125
|
|
|
91
126
|
Start in a Git-backed specs repo such as ${specsRepoName(project)}. GitHub is
|
|
92
127
|
the recommended default when the user has it set up, but any normal repository
|
|
@@ -98,7 +133,13 @@ Use this prompt in the specs repo:
|
|
|
98
133
|
|
|
99
134
|
${airlockPrompt(project)}
|
|
100
135
|
|
|
101
|
-
First ask
|
|
136
|
+
First ask which delivery mode the user wants:
|
|
137
|
+
|
|
138
|
+
1. Spec-first: design governed specs before building the app surface.
|
|
139
|
+
2. App-first: build an app or workflow from existing specs.
|
|
140
|
+
3. Co-development: develop the app and specs together.
|
|
141
|
+
|
|
142
|
+
For spec-first and co-development work, ask: What process do you want to improve?
|
|
102
143
|
|
|
103
144
|
Airlock works best when we can identify the loop around a process:
|
|
104
145
|
|
|
@@ -122,8 +163,34 @@ points, patterns, and ideas. Library specs are not guaranteed to match the
|
|
|
122
163
|
current shape of any third-party system. Prefer current API docs, real exports,
|
|
123
164
|
samples, and other artifacts when they conflict with the library.
|
|
124
165
|
|
|
166
|
+
For governed Markdown knowledge, use the \`okf-knowledge-bundle\` pattern. It
|
|
167
|
+
creates a spec with \`core_config.payload_adapter\` set to
|
|
168
|
+
\`okf_knowledge_bundle\`. Installed Airlock loads locally validated bundles with
|
|
169
|
+
\`airlock.admin.load_okf_bundle(...)\`, can sync parsed metadata with
|
|
170
|
+
\`airlock.admin.sync_okf_bundle_metadata(...)\`, and exposes authoritative
|
|
171
|
+
accepted context through \`AIRLOCK_DATA.ACTIVE.V_OKF_CONCEPT_METADATA\`.
|
|
172
|
+
|
|
125
173
|
Give Codex the messy version of the process. Airlock MCP should help turn it
|
|
126
|
-
into a small first Airlock spec and a plan for more
|
|
174
|
+
into a small first Airlock spec and a plan for more.
|
|
175
|
+
|
|
176
|
+
For app-first and co-development work, give Codex the app goal and available
|
|
177
|
+
specs. Airlock MCP should identify read specs, write specs, orienting views,
|
|
178
|
+
decision capture, and safe Airlock/Snowflake access paths. Installed Airlock
|
|
179
|
+
uses \`observe.*\` for read-only governance observation, \`agent.*\` for
|
|
180
|
+
governed agent work, and \`admin.*\` for administrative mutation. Start
|
|
181
|
+
read-side discovery with observe payloads such as \`observe.procedures\`,
|
|
182
|
+
\`observe.specs\`, \`observe.spec\`, \`observe.governance_map\`,
|
|
183
|
+
\`observe.explain_access\`, \`observe.health\`, \`observe.activity\`,
|
|
184
|
+
\`observe.admin_activity\`, \`observe.spec_admin_activity\`, and \`observe.billing_events\`;
|
|
185
|
+
for \`alter_spec\` activity, use \`CHANGED_SECTIONS\` and \`CHANGED_FIELDS\` to
|
|
186
|
+
triage what changed before fetching version snapshots. Do not use retired admin
|
|
187
|
+
read wrappers such as \`admin.list_specs\`, \`admin.describe_role\`, or
|
|
188
|
+
\`admin.list_events\`. It can
|
|
189
|
+
seed an app repo with \`airlock/specs.manifest.json\`, spec snapshots, sample
|
|
190
|
+
records, and generated helper folders. The app should submit decisions,
|
|
191
|
+
approvals, actions, comments, or follow-ups through Airlock spec contracts, not
|
|
192
|
+
direct table writes.
|
|
193
|
+
In co-development mode, keep the spec track and app track visible side by side.`;
|
|
127
194
|
}
|
|
128
195
|
|
|
129
196
|
export function helpText() {
|
|
@@ -148,5 +215,7 @@ Airlock MCP is the single installed interface for agents working with Airlock.
|
|
|
148
215
|
Spec building is bundled inside that experience.
|
|
149
216
|
Airlock operating patterns help connect specs into OODA loops, separation of
|
|
150
217
|
duties, governed decisions, controlled actions, and feedback loops.
|
|
218
|
+
Airlock MCP can also help build apps and workflows that use existing specs for
|
|
219
|
+
approved reads and governed submissions.
|
|
151
220
|
`;
|
|
152
221
|
}
|
package/src/workbench.mjs
CHANGED
|
@@ -23,6 +23,8 @@ const workspaceProperty = {
|
|
|
23
23
|
maxLength: MAX_ARG_LENGTH,
|
|
24
24
|
};
|
|
25
25
|
|
|
26
|
+
const appModeValues = ["spec-first", "app-first", "co-development"];
|
|
27
|
+
|
|
26
28
|
export const WORKBENCH_TOOLS = [
|
|
27
29
|
{
|
|
28
30
|
name: "airlock_doctor",
|
|
@@ -42,6 +44,32 @@ export const WORKBENCH_TOOLS = [
|
|
|
42
44
|
cwd: cwdProperty,
|
|
43
45
|
}),
|
|
44
46
|
},
|
|
47
|
+
{
|
|
48
|
+
name: "airlock_init_app_context",
|
|
49
|
+
description: "Seed an app repo with airlock/ spec snapshots, samples, generated placeholders, and a manifest.",
|
|
50
|
+
inputSchema: objectSchema({
|
|
51
|
+
path: {
|
|
52
|
+
type: "string",
|
|
53
|
+
description: "App repo path to initialize. Defaults to the current directory.",
|
|
54
|
+
maxLength: MAX_ARG_LENGTH,
|
|
55
|
+
},
|
|
56
|
+
mode: {
|
|
57
|
+
type: "string",
|
|
58
|
+
enum: appModeValues,
|
|
59
|
+
description: "Development mode. Defaults to app-first.",
|
|
60
|
+
},
|
|
61
|
+
specs: {
|
|
62
|
+
type: "array",
|
|
63
|
+
items: {
|
|
64
|
+
type: "string",
|
|
65
|
+
maxLength: MAX_ARG_LENGTH,
|
|
66
|
+
},
|
|
67
|
+
description: "Spec workspace directories or spec JSON files to snapshot.",
|
|
68
|
+
},
|
|
69
|
+
force: forceProperty,
|
|
70
|
+
cwd: cwdProperty,
|
|
71
|
+
}),
|
|
72
|
+
},
|
|
45
73
|
{
|
|
46
74
|
name: "airlock_list_patterns",
|
|
47
75
|
description: "List bundled Airlock spec starter patterns.",
|
|
@@ -54,7 +82,7 @@ export const WORKBENCH_TOOLS = [
|
|
|
54
82
|
{
|
|
55
83
|
pattern: {
|
|
56
84
|
type: "string",
|
|
57
|
-
enum: ["blank", "posts"],
|
|
85
|
+
enum: ["blank", "okf-knowledge-bundle", "posts"],
|
|
58
86
|
description: "Pattern to inspect.",
|
|
59
87
|
},
|
|
60
88
|
files: {
|
|
@@ -78,7 +106,7 @@ export const WORKBENCH_TOOLS = [
|
|
|
78
106
|
},
|
|
79
107
|
pattern: {
|
|
80
108
|
type: "string",
|
|
81
|
-
enum: ["blank", "posts"],
|
|
109
|
+
enum: ["blank", "okf-knowledge-bundle", "posts"],
|
|
82
110
|
description: "Starting pattern. Defaults to blank.",
|
|
83
111
|
},
|
|
84
112
|
output: {
|
|
@@ -230,6 +258,28 @@ function optionalEnum(args, name, allowed, fallback) {
|
|
|
230
258
|
return value;
|
|
231
259
|
}
|
|
232
260
|
|
|
261
|
+
function optionalStringArray(args, name) {
|
|
262
|
+
const value = args?.[name];
|
|
263
|
+
if (value === undefined || value === null) {
|
|
264
|
+
return [];
|
|
265
|
+
}
|
|
266
|
+
if (!Array.isArray(value)) {
|
|
267
|
+
throw new Error(`${name} must be an array`);
|
|
268
|
+
}
|
|
269
|
+
return value.map((entry, index) => {
|
|
270
|
+
if (typeof entry !== "string") {
|
|
271
|
+
throw new Error(`${name}[${index}] must be a string`);
|
|
272
|
+
}
|
|
273
|
+
if (entry.length > MAX_ARG_LENGTH || /[\u0000-\u001f\u007f]/.test(entry)) {
|
|
274
|
+
throw new Error(`${name}[${index}] must be ${MAX_ARG_LENGTH} characters or fewer with no control characters`);
|
|
275
|
+
}
|
|
276
|
+
if (entry.startsWith("-")) {
|
|
277
|
+
throw new Error(`${name}[${index}] must not start with '-'`);
|
|
278
|
+
}
|
|
279
|
+
return entry;
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
233
283
|
function requiredEnum(args, name, allowed) {
|
|
234
284
|
const value = optionalEnum(args, name, allowed, undefined);
|
|
235
285
|
if (value === undefined) {
|
|
@@ -264,6 +314,19 @@ function cliArgsForTool(name, args = {}) {
|
|
|
264
314
|
if (force) cliArgs.push("--force");
|
|
265
315
|
return { cwd, cliArgs };
|
|
266
316
|
}
|
|
317
|
+
case "airlock_init_app_context": {
|
|
318
|
+
const cliArgs = [
|
|
319
|
+
"init-app-context",
|
|
320
|
+
optionalString(args, "path", "."),
|
|
321
|
+
"--mode",
|
|
322
|
+
optionalEnum(args, "mode", appModeValues, "app-first"),
|
|
323
|
+
];
|
|
324
|
+
for (const spec of optionalStringArray(args, "specs")) {
|
|
325
|
+
cliArgs.push("--spec", spec);
|
|
326
|
+
}
|
|
327
|
+
if (force) cliArgs.push("--force");
|
|
328
|
+
return { cwd, cliArgs };
|
|
329
|
+
}
|
|
267
330
|
case "airlock_list_patterns":
|
|
268
331
|
return { cwd, cliArgs: ["list-patterns"] };
|
|
269
332
|
case "airlock_show_pattern": {
|