@reunionstudio/airlock-mcp 0.1.0 → 0.1.2

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.
@@ -20,6 +20,12 @@ the deterministic checker.
20
20
  organization name and suggest `<slug>-specs`; for example, `Home` becomes
21
21
  `home-specs`. Reserve `airlock-specs` for the canonical reusable spec
22
22
  library.
23
+ Recommend storing the specs project in a real version-controlled repo,
24
+ preferably a GitHub repo when the user already uses GitHub. Before creating
25
+ the directory, ask where the user wants the `<slug>-specs` repo to live. If
26
+ Codex can create the repo, offer to initialize git and create/push a GitHub
27
+ repo; otherwise ask the user to create the repo and open it in Codex before
28
+ running `airlock-mcp init-repo`.
23
29
  Public users should normally arrive through the single Airlock MCP install,
24
30
  then ask Airlock to help build and use specs. Treat spec-building as a
25
31
  capability inside that experience, not a second install.
@@ -29,28 +35,53 @@ the deterministic checker.
29
35
  any workspace.
30
36
  If the user opened the public `airlock-mcp` workbench repo as the entry
31
37
  point, help them create a separate `<slug>-specs` project repo beside it.
32
- 3. If no workspace exists, welcome the user and offer three starting paths
33
- before creating files:
34
- - brainstorm possible specs using the OODA loop
35
- - start from a known process and create a blank workspace
36
- - create a `posts` feedback loop where humans and agents can submit
37
- requests, observations, and responses
38
+ 3. If no workspace exists, welcome the user and ask:
39
+ `What process do you want to improve?`
40
+ Explain that Airlock works best when we can identify the loop around that
41
+ process:
42
+ - what information comes in
43
+ - what context helps people or agents understand it
44
+ - what decision needs to be made
45
+ - what action happens after the decision
46
+ Give examples before naming the concept: apps, files, forms, people, emails,
47
+ calls, mail, websites, APIs, data feeds, or physical events. Then call these
48
+ places interfaces: where the process observes from or acts through.
49
+ Ask whether the user already has artifacts for the process, such as CSV or
50
+ Excel files, JSON samples, API docs, schemas, forms, screenshots, PDFs,
51
+ exports, message examples, or other content people already use. A small real
52
+ sample is often better than a long explanation. Remind the user to redact
53
+ secrets before attaching files or pasting content.
54
+ When relevant, look to the reusable `airlock-specs` library for starting
55
+ points, patterns, and ideas. Do not treat those library specs as guaranteed
56
+ descriptions of any third-party system. Prefer current API docs, real data
57
+ exports, samples, and user-provided artifacts when they conflict with the
58
+ library, and record the reason for the divergence.
59
+ Ask for the messy version. Help turn it into a small first Airlock spec and
60
+ a plan for more. Do not create the first workspace until the user chooses a
61
+ path.
38
62
  4. Create `posts` only when the user chooses a feedback loop, asks for humans
39
63
  and agents to provide feedback, or explicitly requests the posts pattern.
40
- If the user is unsure, offer OODA brainstorming first.
64
+ If the user is unsure, continue process discovery before creating files.
41
65
  5. Use `airlock-mcp import-spec <json-file> <name>` when starting from a
42
66
  spec-library file, an exported `SPEC_CONFIG`, or an existing canonical config.
67
+ If the source is from `airlock-specs`, treat it as a reusable draft pattern.
68
+ Check actual API docs, CSV/Excel/JSON samples, schemas, or other artifacts
69
+ before assuming the source fields match a live third-party system.
43
70
  6. Use `airlock-mcp clone <source-workspace> <name>` when creating a related
44
71
  draft from an existing workspace. Treat clone like the old Streamlit UI:
45
72
  preserve the shape but deliberately reset spec identity.
46
73
  7. Keep the draft small. Prefer one useful governed output over a large
47
- speculative system.
74
+ speculative system, then keep a plan for later specs.
48
75
  8. On later sessions, run `airlock-mcp list-workspaces` when the target draft
49
76
  is not obvious.
50
77
  9. Run `airlock-mcp summary <workspace>` and
51
78
  `airlock-mcp next <workspace>` before editing so
52
79
  the current shape, sample count, access model, and local check status are
53
80
  visible.
81
+ Present the summary back to the user as a structured spec card when useful:
82
+ core, file rules, attachments, guest access, column rules, samples, notes,
83
+ and check status. Do not make the user infer the current spec from file
84
+ links alone.
54
85
  10. Run `airlock-mcp check <workspace>` after changing draft config or sample
55
86
  records.
56
87
  11. Keep `sample.records.json` as the agent-friendly authoring shape. Use
@@ -63,7 +94,9 @@ the deterministic checker.
63
94
 
64
95
  ## Spec Design Questions
65
96
 
66
- Resolve these in order, and write the answers into `decisions.md`:
97
+ Use these as an internal checklist. Do not dump the whole list into chat.
98
+ Write resolved answers into `decisions.md` and ask the human only for missing
99
+ or risky decisions:
67
100
 
68
101
  1. What is one row about?
69
102
  2. What systems, users, files, events, or reference data must be observed before
@@ -79,17 +112,52 @@ Resolve these in order, and write the answers into `decisions.md`:
79
112
  10. Which optional context can live in a validated `variant` field?
80
113
  11. Who submits, reviews, reads, delegates, and owns the process?
81
114
 
115
+ ## Interfaces
116
+
117
+ Use interface to mean any place the process observes from or acts through.
118
+ Do not lead with the word before examples. Interfaces can be apps, files, forms,
119
+ people, emails, calls, mail, websites, APIs, data feeds, physical events,
120
+ shared folders, payment tools, bank apps, or other systems.
121
+
122
+ When a user names a process, map the interfaces both ways:
123
+
124
+ - Observe: where information enters the loop.
125
+ - Act: where a decision writes back to the world.
126
+
127
+ Spot gaps gently. A user may have one dataset but need additional observations
128
+ to orient well, or may rely on hard-to-automate interfaces such as phone calls
129
+ or physical mail.
130
+
131
+ ## Artifacts And Libraries
132
+
133
+ Start from artifacts whenever they exist. Useful design artifacts include CSV
134
+ or Excel files, JSON samples, API docs, schemas, forms, screenshots, PDFs,
135
+ exports, message examples, and other defined content that already carries the
136
+ process shape.
137
+
138
+ Use design artifacts to infer row grain, field names, durable identifiers,
139
+ timestamps, evidence, variants, attachment needs, and edge cases. Distinguish
140
+ design artifacts from Airlock attachments: design artifacts help draft the spec;
141
+ attachments are evidence files later submitted with governed records.
142
+
143
+ Use `airlock-specs` as a source of reusable starting points, patterns, and
144
+ ideas. Do not promise that Airlock spec-library shapes reflect current
145
+ third-party APIs, exports, or business objects. If a library shape looks
146
+ outdated, overfit, underfit, or contradicted by current artifacts, override it
147
+ with the best current evidence and explain the decision in `decisions.md` or
148
+ `review.md`.
149
+
82
150
  ## OODA Loop
83
151
 
84
152
  Use the observe-orient-decide-act loop as the product frame:
85
153
 
86
- - Observe: source systems, human signals, files, screenshots, exports, APIs,
87
- reference specs, and prior Airlock outputs.
88
- - Orient: row grain, field types, access model, evidence, workflow, references,
89
- expectations, and risk.
90
- - Decide: the smallest governed output worth creating now.
91
- - Act: validate locally, create in Airlock, collect real records, then extend or
92
- add the next spec based on feedback.
154
+ - Observe: controlled interface ingestion and observation/reference specs.
155
+ - Orient: context, proposals, scoring, exception queues, summaries, and gaps in
156
+ the observation set.
157
+ - Decide: governed choices by people or agents, with identity, timestamp,
158
+ rationale, evidence, approval, and separation of duties.
159
+ - Act: controlled writes back to interfaces, commitments, follow-ups, outputs,
160
+ and the next observations created by those actions.
93
161
 
94
162
  ## Pattern Guidance
95
163
 
@@ -1,4 +1,4 @@
1
1
  interface:
2
2
  display_name: "Airlock MCP"
3
- short_description: "Draft and review Airlock specs with Codex."
4
- default_prompt: "Use $airlock-mcp to help me draft a small Airlock spec, choose a starting pattern, and check the local workspace."
3
+ short_description: "Improve a process with Airlock specs and OODA loop planning."
4
+ default_prompt: "Use $airlock-mcp to ask what process I want to improve, gather any existing artifacts, identify the loop around it, draft a small first Airlock spec, and keep a plan for more specs."
package/README.md CHANGED
@@ -5,18 +5,21 @@ Airlock.
5
5
 
6
6
  It covers the full Airlock loop:
7
7
 
8
- - build specs with the bundled spec-building workbench
9
- - use specs to pull and push governed data with the Airlock Star capability
8
+ - design specs with the bundled spec-building workbench
9
+ - map the process a person wants to improve into observe, orient, decide, and act
10
+ - use specs for governed data movement, decisions, actions, and feedback loops
10
11
  - validate, create, and revise specs against installed Airlock
11
- - capture real use cases and improvements so specs get better over time
12
12
 
13
13
  Spec building is not a second thing users install. It is bundled inside
14
14
  Airlock MCP.
15
15
 
16
- Airlock Star is not a second thing users install either. It is the capability
17
- inside Airlock MCP for working through real Airlock use cases,
18
- pulling and pushing data through specs, reading outputs, and turning experience
19
- back into better specs.
16
+ Airlock MCP gives agents two kinds of Airlock expertise:
17
+
18
+ 1. Spec design: draft, check, revise, import, clone, and prepare specs for
19
+ installed Airlock validation.
20
+ 2. Airlock operating patterns: use specs to organize observations, orientation,
21
+ governed decisions, controlled actions, separation of duties, and feedback
22
+ loops.
20
23
 
21
24
  ## Install
22
25
 
@@ -26,7 +29,7 @@ Dogfood directly from GitHub:
26
29
  npx -y github:reunionstudio/airlock-mcp install --package github:reunionstudio/airlock-mcp
27
30
  ```
28
31
 
29
- After the npm package is published, use:
32
+ Install from npm:
30
33
 
31
34
  ```bash
32
35
  npx @reunionstudio/airlock-mcp install
@@ -45,9 +48,14 @@ The GitHub dogfood command registers:
45
48
  codex mcp add airlock -- npx -y github:reunionstudio/airlock-mcp server
46
49
  ```
47
50
 
48
- The server exposes bootstrap guidance for starting a specs repo and entering
49
- the bundled spec-building workbench or the Airlock Star use-and-improve
50
- capability.
51
+ The server exposes bootstrap guidance for starting a specs repo, coaching a
52
+ person through process discovery, and entering the bundled spec-building
53
+ workbench when a first spec is ready to draft.
54
+
55
+ Workspace summaries are structured spec cards. They present the current spec
56
+ core, file rules, attachment policy, guest access, column rules, sample record
57
+ shape, note-file status, and local check status so Codex can reflect the draft
58
+ back to the user before asking for decisions.
51
59
 
52
60
  This install shape uses Node because `npx` runs npm package binaries. MCP itself
53
61
  does not require Node. Once Airlock MCP does real operational work, such as
@@ -81,7 +89,7 @@ The server exposes orientation plus local spec-building tools:
81
89
 
82
90
  - `airlock_start`: return setup guidance for a project.
83
91
  - `airlock_doctor`: verify bundled workbench assets.
84
- - `airlock_init_repo`: bootstrap a blank specs repo.
92
+ - `airlock_init_repo`: bootstrap a Git-backed specs repo.
85
93
  - `airlock_list_patterns` and `airlock_show_pattern`: inspect starter patterns.
86
94
  - `airlock_init_workspace`: create a workspace from `blank` or `posts`.
87
95
  - `airlock_list_workspaces`: inspect active or archived drafts.
@@ -114,13 +122,27 @@ The intended user flow is:
114
122
 
115
123
  1. Run `npx @reunionstudio/airlock-mcp install` once for the agent environment.
116
124
  2. Open Codex.
117
- 3. Create a blank project repo named for the org or project, such as
118
- `home-specs`.
119
- 4. Ask Codex to use Airlock MCP to help build specs and use specs with
120
- Airlock Star.
121
- 5. Let Airlock MCP bootstrap the project, welcome the user, and offer the next
122
- useful path before creating the first workspace.
125
+ 3. Create or open a Git-backed specs repo named for the org or project, such as
126
+ `home-specs`. GitHub is the recommended default when available.
127
+ 4. If Codex is creating the repo, choose where the `home-specs` directory should
128
+ live before files are written.
129
+ 5. Ask Codex to use Airlock MCP to help improve a process with Airlock specs.
130
+ 6. Let Airlock MCP bootstrap the project, ask what process the user wants to
131
+ improve, and propose a small first spec plus a plan for more.
123
132
 
124
133
  The first workspace should not be created automatically. The spec-building
125
- workbench should offer OODA brainstorming, a known-process draft, or a shared
126
- `posts` feedback loop.
134
+ workbench should first ask for the messy process, identify where information
135
+ comes in and actions go out, then choose a small observation, orient, decision,
136
+ or action spec.
137
+
138
+ When the user already has artifacts, Airlock MCP should ask for them early:
139
+ CSV or Excel files, JSON samples, API docs, schemas, forms, screenshots, PDFs,
140
+ exports, message examples, or other defined content people already use. These
141
+ are design artifacts for drafting the spec; later Airlock attachments are
142
+ evidence files submitted with governed records.
143
+
144
+ Airlock MCP can also consult the reusable `airlock-specs` library for starting
145
+ points, patterns, and ideas. Those library specs are not guaranteed to reflect
146
+ the current shape of any third-party system. Current API docs, real exports,
147
+ samples, schemas, and user-provided artifacts should override library shapes
148
+ when they conflict.
@@ -28,9 +28,10 @@ heavier operational tools mature.
28
28
 
29
29
  The spec-building workbench lives in this repo under `src/airlock_mcp`,
30
30
  `patterns`, `workspaces`, `schemas`, and `.agents/skills/airlock-mcp`.
31
- Airlock Star is the use-and-improve capability inside Airlock MCP: real use
32
- cases, governed pull/push through specs, output review, and improvement capture.
33
- It is also not a second install.
31
+ Airlock operating patterns live in the same MCP experience: real use cases,
32
+ controlled interface ingestion, OODA loops, governed decisions, separation of
33
+ duties, controlled actions, output review, and improvement capture. This is not
34
+ a second install or separate product surface.
34
35
 
35
36
  ## MCP Surface
36
37
 
@@ -44,10 +45,10 @@ The bootstrap server exposes:
44
45
  `airlock_list_workspaces`, `airlock_check_workspace`, `airlock_summary`,
45
46
  `airlock_next`, `airlock_export_csv`, and `airlock_render_sql`
46
47
 
47
- These give the agent enough context to start a blank `<project>-specs` repo,
48
- enter the spec-building workbench when specs need drafting, enter Star when
49
- specs need to be used or improved, and avoid creating a first workspace until
50
- the user chooses a path.
48
+ These give the agent enough context to start a Git-backed `<project>-specs`
49
+ repo in a user-chosen location, ask what process the user wants to improve,
50
+ enter the spec-building workbench when a first spec is ready to draft, and
51
+ avoid creating a first workspace until the user chooses a path.
51
52
 
52
53
  Workbench tools call the bundled Python package with argument arrays and a
53
54
  controlled `PYTHONPATH`. They do not expose update commands over MCP. Tool
@@ -12,9 +12,12 @@ npx @reunionstudio/airlock-mcp install
12
12
  ```
13
13
 
14
14
  Airlock MCP is the single installed interface for agents working with Airlock.
15
- Then the user opens Codex, creates a blank `<project>-specs` repo, and starts
16
- chatting with Airlock. Airlock MCP should cover building specs, using specs to
17
- pull and push governed data, and capturing improvements from real use cases.
15
+ Then the user opens Codex, creates or opens a Git-backed `<project>-specs`
16
+ repo, and starts chatting with Airlock. GitHub is the recommended default when
17
+ available. If Codex is creating the repo, it should ask where the directory
18
+ should live before writing files. Airlock MCP should start by asking what
19
+ process the user wants to improve, then help design specs and operating
20
+ patterns around observe, orient, decide, and act.
18
21
 
19
22
  The install command is not the spec workspace. It is the connector/setup entry
20
23
  point. The specs repo is still the durable memory.
@@ -106,7 +109,13 @@ packaging pressure appears.
106
109
  The first release should optimize the user journey:
107
110
 
108
111
  1. install connector
109
- 2. create blank `<project>-specs` Codex project
110
- 3. bootstrap the spec-building capability when specs need drafting
111
- 4. help the user use specs to validate, load, read, push, and pull data
112
- 5. create the first workspace only after the user chooses a path
112
+ 2. create or open a Git-backed `<project>-specs` Codex project
113
+ 3. ask where the repo directory should live if Codex is creating it
114
+ 4. ask what process the user wants to improve
115
+ 5. ask for existing artifacts such as CSV, Excel, JSON, API docs, schemas,
116
+ forms, screenshots, PDFs, exports, or message examples
117
+ 6. use `airlock-specs` library patterns as starting points when useful, while
118
+ preferring current artifacts over library shapes when they conflict
119
+ 7. map where information comes in and actions go out
120
+ 8. create the first workspace only after the user chooses a small first spec
121
+ 9. keep a plan for later specs that improve the full loop
package/docs/ooda-loop.md CHANGED
@@ -1,21 +1,38 @@
1
1
  # OODA Loop For Airlock Specs
2
2
 
3
- Airlock specs should support a business loop, not just a table.
3
+ Airlock specs should support a process loop, not just a table.
4
+
5
+ Airlock works best when we can identify where information comes in and where
6
+ actions go out. Those places might be apps, files, forms, people, emails, calls,
7
+ mail, websites, APIs, data feeds, physical events, payment tools, bank apps, or
8
+ shared folders. After those examples are clear, call them interfaces: where the
9
+ process observes from or acts through.
10
+
11
+ Start from existing artifacts when they exist: CSV or Excel files, JSON samples,
12
+ API docs, schemas, forms, screenshots, PDFs, exports, message examples, or other
13
+ defined content people already use. A real sample often reveals identifiers,
14
+ timestamps, optional fields, and edge cases faster than chat can.
15
+
16
+ The reusable `airlock-specs` library can provide starting points, patterns, and
17
+ ideas. It is not a guarantee of the current shape of any third-party API,
18
+ export, or business object. Current docs and actual samples should override the
19
+ library when they conflict.
4
20
 
5
21
  ## Observe
6
22
 
7
- Name the evidence and systems that matter:
23
+ Name the interfaces, evidence, and signals that matter:
8
24
 
9
25
  - human entries
10
26
  - agent observations
11
27
  - screenshots, PDFs, receipts, exports, or source files
28
+ - CSV, Excel, JSON, API docs, schemas, forms, or message examples
12
29
  - source APIs or app objects
13
30
  - existing Airlock specs or reference data
14
31
  - downstream system state
15
32
 
16
33
  ## Orient
17
34
 
18
- Turn observations into a governed shape:
35
+ Turn observations into context that can support a decision:
19
36
 
20
37
  - one row grain
21
38
  - durable identifiers
@@ -27,14 +44,20 @@ Turn observations into a governed shape:
27
44
  - workflow
28
45
  - references
29
46
  - expectations
47
+ - missing observations or quality gaps
30
48
 
31
49
  ## Decide
32
50
 
33
- Choose the smallest governed output worth creating now. If uncertainty is high,
34
- start with `posts` and let real feedback shape the next spec.
51
+ Capture the governed choice. A decision spec should identify who or what made
52
+ the choice, when it happened, which option was selected, what evidence or
53
+ rationale mattered, and what separation of duties applies.
35
54
 
36
55
  ## Act
37
56
 
38
- Create the spec in Airlock only after local drafting is coherent. Then collect
39
- records, review them, and decide whether to revise the spec or add the next
40
- small spec.
57
+ Model the action that follows the decision: send an email, submit payment,
58
+ update a website, change a price, open a ticket, trigger outreach, produce a
59
+ filing, request more evidence, or create another governed output. The action
60
+ creates new observations and the loop spins again.
61
+
62
+ Start with one small useful spec, then keep a plan for the next specs that
63
+ complete or improve the loop.
@@ -125,8 +125,9 @@ patterns, bootstrap, workspace files, local checks, and the Codex skill.
125
125
 
126
126
  That command is the agent connector/setup entry point, not the user's spec
127
127
  workspace. After installing or registering the connector, the user still creates
128
- a separate `<project>-specs` repo and works there with Codex. Users should ask
129
- for Airlock, not install a separate spec-building tool.
128
+ or opens a separate Git-backed `<project>-specs` repo in a user-chosen location
129
+ and works there with Codex. GitHub is the recommended default when available.
130
+ Users should ask for Airlock, not install a separate spec-building tool.
130
131
 
131
132
  For Codex, the install command should use the platform MCP manager rather than
132
133
  editing config files directly:
package/docs/workflows.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Start A New Specs Repo
4
4
 
5
- Use this when a person opens a blank Codex project and wants to start working
5
+ Use this when a person opens a new Codex project and wants to start working
6
6
  with real Airlock specs. The project repo is where they work. Public users
7
7
  should come through the single Airlock MCP install; this repo provides the
8
8
  spec-building capability behind that experience.
@@ -10,6 +10,11 @@ spec-building capability behind that experience.
10
10
  Ask for the project or organization name first, then lowercase it, replace
11
11
  spaces with hyphens, and append `-specs`. For example, `Home` becomes
12
12
  `home-specs`. Reserve `airlock-specs` for the canonical reusable spec library.
13
+ Recommend a real Git repo for the specs project. GitHub is the recommended
14
+ default when the user already has GitHub set up, but any normal repository host
15
+ is acceptable. If Codex is creating the repo, ask where the `<slug>-specs`
16
+ directory should live before making files, then offer to initialize git and
17
+ create or push the GitHub repo.
13
18
  Airlock itself does not create this repo; Codex can create it locally while
14
19
  helping the user start an Airlock specs project.
15
20
  Start in Codex, not Snowflake Cortex. Snow CLI or Cortex only matters later when
@@ -20,10 +25,22 @@ The preferred Codex prompt is:
20
25
  ```text
21
26
  I want to use Airlock MCP to start working with Airlock specs for Home.
22
27
 
23
- Set up this project as an Airlock specs repo. Use the Airlock MCP
24
- spec-building capability when we need to draft or revise specs. Welcome me,
25
- help me think through real Airlock use cases, and ask only for the missing
26
- decisions. Do not create the first workspace until I choose a path.
28
+ Set up this project as an Airlock specs repo. If this project is not already a
29
+ Git repo, recommend storing it in version control, preferably GitHub if
30
+ available. If you are creating the repo for me, ask where the `home-specs`
31
+ directory should live before making files.
32
+
33
+ Welcome me by asking what process I want to improve. Explain that Airlock works
34
+ best when we can identify the loop around that process: what information comes
35
+ in, what context helps us understand it, what decision needs to be made, and
36
+ what action happens after the decision. Ask whether I already have artifacts:
37
+ CSV or Excel files, JSON samples, API docs, schemas, forms, screenshots, PDFs,
38
+ exports, message examples, or other content people already use. When useful,
39
+ check the reusable airlock-specs library for starting points, patterns, and
40
+ ideas, but prefer current API docs, real exports, samples, and other artifacts
41
+ when they conflict with a library shape. Ask for the messy version, then help
42
+ turn it into a small first Airlock spec and a plan for more. Do not create the
43
+ first workspace until I choose a path.
27
44
  ```
28
45
 
29
46
  When dogfooding this implementation repo before the MCP package is published,
@@ -50,9 +67,10 @@ The connector implementation lives in `reunionstudio/airlock-mcp`; this
50
67
  workbench keeps the Airlock MCP spec-building capability.
51
68
 
52
69
  That should install or register the Airlock MCP connector for the user's agent
53
- environment. After that, the user still creates a blank `<slug>-specs` project
54
- and starts chatting there. Airlock MCP covers building specs, using specs to
55
- pull and push governed data, and improving specs from real use cases.
70
+ environment. After that, the user still creates or opens a Git-backed
71
+ `<slug>-specs` project and starts chatting there. Airlock MCP covers building
72
+ specs, using specs to pull and push governed data, and improving specs from real
73
+ use cases.
56
74
 
57
75
  For Codex, the install command should register the server with:
58
76
 
@@ -64,28 +82,59 @@ The MCP-style flow should be:
64
82
 
65
83
  1. Run `npx @reunionstudio/airlock-mcp install` once for the agent environment.
66
84
  2. Open Codex.
67
- 3. Create a new blank project named for the org or project, such as
85
+ 3. Create or open a Git-backed specs repo named for the org or project, such as
68
86
  `home-specs`.
69
- 4. Tell Codex: `Use Airlock to help me build and use specs.`
70
- 5. Airlock MCP welcomes, offers OODA brainstorming, a known-process draft, a
71
- `posts` feedback loop, or installed-Airlock validation/use.
87
+ 4. If Codex is creating it, choose where the repo directory should live before
88
+ files are written.
89
+ 5. Tell Codex: `Use Airlock to help me improve a process with specs.`
90
+ 6. Airlock MCP welcomes, asks what process the user wants to improve, explains
91
+ the loop around the process, and proposes a small first spec plus a plan for
92
+ more.
72
93
 
73
94
  `init-repo` creates `AGENTS.md`, `.agents/skills/airlock-mcp/SKILL.md`, and
74
95
  `workspaces/`. That is what lets Codex understand prompts such as
75
96
  `Use $airlock-mcp` inside the specs repo.
76
97
 
77
- After bootstrap, offer three paths before creating a workspace:
98
+ After bootstrap, do not start with a pattern picker. Ask:
78
99
 
79
- - brainstorm possible specs using the OODA loop
80
- - start from a known process and create a blank workspace
81
- - create a `posts` feedback loop for humans and agents to submit requests,
82
- observations, and responses
100
+ ```text
101
+ What process do you want to improve?
102
+ ```
103
+
104
+ Then explain:
105
+
106
+ - Airlock works best when we can identify what information comes in.
107
+ - Airlock works best when we can identify what context helps people or agents
108
+ understand that information.
109
+ - Airlock works best when we can identify what decision needs to be made.
110
+ - Airlock works best when we can identify what action happens after the
111
+ decision.
112
+
113
+ Information may come from apps, files, forms, people, emails, calls, mail,
114
+ websites, APIs, data feeds, or physical events. Actions may go back through
115
+ those same places. After giving examples, call these places interfaces: where
116
+ the process observes from or acts through.
117
+
118
+ Ask whether the user already has artifacts for the process: CSV or Excel files,
119
+ JSON samples, API docs, schemas, forms, screenshots, PDFs, exports, message
120
+ examples, or other content people already use. Treat these as design artifacts
121
+ for drafting the spec. They are different from Airlock attachments, which are
122
+ evidence files submitted later with governed records.
123
+
124
+ When useful, point at the reusable `airlock-specs` library for starting points,
125
+ patterns, and ideas. Do not treat those library specs as guaranteed to reflect
126
+ the current shape of third-party systems. If current API docs, exports, samples,
127
+ schemas, or user-provided artifacts disagree with the library, prefer the
128
+ current artifacts and record the divergence.
129
+
130
+ Ask for the messy version. Help turn it into a small first Airlock spec and a
131
+ plan for more.
83
132
 
84
133
  ## Start From Feedback
85
134
 
86
135
  Use this when the user chooses a shared feedback loop for humans and agents.
87
- If they are not sure what to model yet, offer OODA brainstorming before creating
88
- this workspace.
136
+ If they are not sure what to model yet, continue process discovery before
137
+ creating this workspace.
89
138
 
90
139
  ```bash
91
140
  airlock-mcp init feedback-loop --pattern posts
@@ -124,6 +173,11 @@ Supported input shapes:
124
173
  - a raw canonical object with `core_config` or `column_config`
125
174
  - a legacy `{"specs": [{"config": ...}]}`
126
175
 
176
+ Spec-library imports are starting points, not live system contracts. Before
177
+ using one for a third-party system, compare it with current API docs, CSV or
178
+ Excel exports, JSON samples, schemas, forms, and other real artifacts. Override
179
+ outdated or mismatched fields when current evidence says the shape has changed.
180
+
127
181
  ## Clone A Workspace
128
182
 
129
183
  Use this when a related spec should preserve most design choices but needs a new
@@ -167,7 +221,10 @@ airlock-mcp next workspaces/team-posts
167
221
 
168
222
  The summary shows the current spec identity, required fields, variant fields,
169
223
  attachment posture, guest access model, sample record count, note-file status,
170
- and local check counts.
224
+ and local check counts. It is organized as a structured spec card with sections
225
+ for core, file rules, attachments, guest access, column rules, samples, notes,
226
+ and check status so Codex can present the draft back to the user before asking
227
+ for decisions.
171
228
 
172
229
  `next` prints the same recap plus a conservative next action: fix local errors,
173
230
  review warnings, fill open design prompts in `decisions.md`, add sample records,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reunionstudio/airlock-mcp",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Single-install MCP interface for Airlock agents.",
5
5
  "type": "module",
6
6
  "repository": {
package/setup.py CHANGED
@@ -27,7 +27,7 @@ def data_files():
27
27
 
28
28
  setup(
29
29
  name="airlock-mcp",
30
- version="0.1.0",
30
+ version="0.1.2",
31
31
  description="Codex-first workbench and CLI for drafting Airlock specs.",
32
32
  packages=find_packages("src"),
33
33
  package_dir={"": "src"},
@@ -1,3 +1,3 @@
1
1
  """Airlock MCP CLI package."""
2
2
 
3
- __version__ = "0.1.0"
3
+ __version__ = "0.1.2"
@@ -29,6 +29,13 @@ Reserve `airlock-specs` for the canonical reusable Airlock spec library. A
29
29
  team, customer, domain, or project should use its own scoped repo name such as
30
30
  `home-specs`, `acme-finance-specs`, or `customer-onboarding-specs`.
31
31
 
32
+ Specs work should live in a real version-controlled repo. Prefer GitHub when
33
+ the user already uses GitHub, but any normal Git host is acceptable. Before
34
+ creating a new `<slug>-specs` directory, ask where it should live. If Codex can
35
+ create the repo, offer to initialize git and create or push the GitHub repo. If
36
+ not, ask the user to create the repo and open it in Codex before bootstrapping
37
+ Airlock MCP files.
38
+
32
39
  Airlock itself does not create this repo. Codex can create it locally while
33
40
  helping the user start an Airlock MCP project, then Airlock receives the
34
41
  finished spec later. Start in Codex, not Snowflake Cortex. Snow CLI or Cortex
@@ -37,23 +44,47 @@ installed Airlock app.
37
44
 
38
45
  ## Starting A Spec Project
39
46
 
40
- After bootstrap, welcome the user and orient before creating a workspace. Ask
41
- whether they want to:
47
+ After bootstrap, welcome the user and orient before creating a workspace. Start
48
+ with:
49
+
50
+ What process do you want to improve?
51
+
52
+ Explain that Airlock works best when we can identify the loop around that
53
+ process:
54
+
55
+ 1. what information comes in
56
+ 2. what context helps people or agents understand it
57
+ 3. what decision needs to be made
58
+ 4. what action happens after the decision
59
+
60
+ Information may come from apps, files, forms, people, emails, calls, mail,
61
+ websites, APIs, data feeds, or physical events. Actions may go back through
62
+ those same places. After giving examples, call these places interfaces: where
63
+ the process observes from or acts through.
64
+
65
+ Ask whether the user already has artifacts for the process: CSV or Excel files,
66
+ JSON samples, API docs, schemas, forms, screenshots, PDFs, exports, message
67
+ examples, or other defined content people already use. A small real sample is
68
+ often better than a long explanation. Remind the user to redact secrets before
69
+ attaching files or pasting content.
42
70
 
43
- - brainstorm possible specs with the OODA loop
44
- - start from a known process they already have in mind
45
- - create a shared `posts` feedback loop for humans and agents to submit
46
- requests, observations, and responses
71
+ Use `airlock-specs` as a reusable library of starting points, patterns, and
72
+ ideas when it is available. Do not assume library specs match the current shape
73
+ of a third-party API, export, or business object. Prefer current API docs, real
74
+ data exports, samples, and user-provided artifacts when they conflict with the
75
+ library, and record the reason for the divergence.
47
76
 
48
- Create `posts` only when the user chooses a feedback loop or explicitly asks
49
- for the posts pattern.
77
+ Ask for the messy version. Help turn it into a small first Airlock spec and a
78
+ plan for more. Do not create the first workspace until the user chooses a path.
79
+ Create `posts` only when the user wants a shared feedback loop or explicitly
80
+ asks for the posts pattern.
50
81
 
51
82
  ## Working Style
52
83
 
53
84
  - Use the repo-scoped `$airlock-mcp` skill for spec drafting, review, and
54
85
  pattern selection.
55
86
  - Keep drafts small and concrete. Prefer one useful governed output over a
56
- large speculative process map.
87
+ large speculative process map, then keep a plan for later specs.
57
88
  - Preserve decisions in workspace files so future Codex sessions can resume
58
89
  without relying on chat memory.
59
90
  - Use `airlock-mcp list-workspaces` before guessing which draft to resume.
@@ -78,6 +109,11 @@ Resolve these before final JSON:
78
109
  - workflow and pushback
79
110
  - references and expectations
80
111
  - delegation and agent identity
112
+ - interfaces observed from or acted through
113
+ - existing artifacts such as CSV, Excel, JSON, API docs, schemas, exports,
114
+ forms, screenshots, PDFs, or message examples
115
+ - whether an `airlock-specs` library pattern was used, changed, or rejected
116
+ - likely gaps in observations, orientation, decisions, or actions
81
117
  - observe-orient-decide-act loop
82
118
 
83
119
  Do not encode Airlock lifecycle state, reviewer notes, approval status, or
@@ -154,8 +190,9 @@ def format_bootstrap_result(result: BootstrapResult) -> str:
154
190
  "",
155
191
  "next:",
156
192
  "1. Open this repo in Codex.",
157
- "2. Ask: Use Airlock to help me build and use specs.",
158
- "3. Choose OODA brainstorming, a known process, or a posts feedback loop.",
193
+ "2. Keep this specs project in git; GitHub is recommended when available.",
194
+ "3. Ask: Use Airlock to help me build and use specs.",
195
+ "4. Start with: What process do you want to improve?",
159
196
  ]
160
197
  )
161
198
  return "\n".join(lines)
@@ -303,7 +303,7 @@ def build_parser() -> argparse.ArgumentParser:
303
303
  about_parser = subparsers.add_parser("about", help="Show the Airlock MCP mark and command map.")
304
304
  about_parser.set_defaults(func=about)
305
305
 
306
- init_repo_parser = subparsers.add_parser("init-repo", help="Prepare a specs repo for Codex and Airlock MCP.")
306
+ init_repo_parser = subparsers.add_parser("init-repo", help="Prepare a Git-backed specs repo for Codex and Airlock MCP.")
307
307
  init_repo_parser.add_argument("path", nargs="?", default=".", help="Specs repo path. Defaults to current directory.")
308
308
  init_repo_parser.add_argument("--force", action="store_true", help="Overwrite AGENTS.md and the repo-scoped skill.")
309
309
  init_repo_parser.set_defaults(func=init_repo)
@@ -233,8 +233,24 @@ def next_steps(workspace: Path) -> str:
233
233
  lines.append(f"2. Run `airlock-mcp summary {workspace}` to confirm the shape.")
234
234
  return "\n".join(lines)
235
235
  if _text_has_open_placeholders(workspace / "decisions.md"):
236
- lines.append("1. Fill in decisions.md for row grain, identifiers, time, evidence, access, and OODA.")
237
- lines.append(f"2. Run `airlock-mcp next {workspace}` when the design notes are current.")
236
+ spec_name = ""
237
+ if isinstance(spec, dict):
238
+ core_config = spec.get("core_config")
239
+ if isinstance(core_config, dict):
240
+ spec_name = str(core_config.get("spec_name") or "")
241
+ if spec_name == "posts":
242
+ lines.append("1. Record the starter assumptions in decisions.md, or change only what is wrong.")
243
+ lines.append(
244
+ "2. Defaults: one row is one post/request/observation/response; "
245
+ "submitters are the owner and approved agents; evidence is optional; "
246
+ "posted_at is authored or captured time."
247
+ )
248
+ lines.append("3. Use posts to collect messy process feedback, then plan the first observe, orient, decide, or act spec.")
249
+ else:
250
+ lines.append("1. Record the messy process goal and first-loop assumptions in decisions.md.")
251
+ lines.append("2. Identify what is observed, what helps orient, what decision is governed, and what action follows.")
252
+ lines.append("3. Keep the first spec small and note later specs in review.md.")
253
+ lines.append(f"4. Run `airlock-mcp next {workspace}` when the design notes are current.")
238
254
  return "\n".join(lines)
239
255
  records = sample.get("records") if isinstance(sample, dict) else []
240
256
  if not records:
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import json
3
4
  from pathlib import Path
4
5
  from typing import Any
5
6
 
@@ -30,6 +31,40 @@ def _variant_shape_fields(spec_config: dict[str, Any]) -> set[str]:
30
31
  return fields
31
32
 
32
33
 
34
+ def _format_value(value: Any, *, default: str = "unknown") -> str:
35
+ if value is None:
36
+ return default
37
+ if isinstance(value, bool):
38
+ return "true" if value else "false"
39
+ if isinstance(value, (dict, list)):
40
+ text = json.dumps(value, sort_keys=True, separators=(",", ":"))
41
+ else:
42
+ text = str(value)
43
+ return text if text else default
44
+
45
+
46
+ def _format_literal(value: Any, *, default: str = "unknown") -> str:
47
+ if value is None:
48
+ return default
49
+ if isinstance(value, bool):
50
+ return "true" if value else "false"
51
+ if isinstance(value, str):
52
+ return json.dumps(value)
53
+ return str(value)
54
+
55
+
56
+ def _join(values: list[str], *, default: str = "none") -> str:
57
+ cleaned = [value for value in values if value]
58
+ return ", ".join(cleaned) if cleaned else default
59
+
60
+
61
+ def _truncate(value: Any, limit: int = 96) -> str:
62
+ text = _format_value(value, default="")
63
+ if len(text) <= limit:
64
+ return text
65
+ return text[: limit - 3] + "..."
66
+
67
+
33
68
  def _guest_access_summary(spec_config: dict[str, Any]) -> str:
34
69
  guest_access = spec_config.get("guest_access")
35
70
  if not isinstance(guest_access, dict):
@@ -50,6 +85,34 @@ def _guest_access_summary(spec_config: dict[str, Any]) -> str:
50
85
  return "shared public folder: " + (", ".join(enabled) if enabled else "no enabled subfolders")
51
86
 
52
87
 
88
+ def _enabled_guest_subfolders(guest_access: dict[str, Any]) -> list[str]:
89
+ public_folder = guest_access.get("public_folder")
90
+ if not isinstance(public_folder, dict):
91
+ return []
92
+ subfolders = public_folder.get("subfolders")
93
+ if not isinstance(subfolders, dict):
94
+ return []
95
+ return [
96
+ str(name)
97
+ for name, value in subfolders.items()
98
+ if isinstance(value, dict) and value.get("enabled") is True
99
+ ]
100
+
101
+
102
+ def _guest_role_lines(guest_access: dict[str, Any]) -> list[str]:
103
+ roles = guest_access.get("guest_roles")
104
+ if not isinstance(roles, list):
105
+ return []
106
+ lines: list[str] = []
107
+ for role in roles:
108
+ if not isinstance(role, dict):
109
+ continue
110
+ role_name = _format_value(role.get("role_name"))
111
+ access_level = _format_value(role.get("access_level"))
112
+ lines.append(f"{role_name} -> {access_level}")
113
+ return lines
114
+
115
+
53
116
  def _attachment_summary(spec_config: dict[str, Any]) -> str:
54
117
  policy = spec_config.get("attachment_policy")
55
118
  if not isinstance(policy, dict):
@@ -59,6 +122,86 @@ def _attachment_summary(spec_config: dict[str, Any]) -> str:
59
122
  return "required" if policy.get("attachment_required") is True else "optional"
60
123
 
61
124
 
125
+ def _column_tests(column: dict[str, Any]) -> list[str]:
126
+ tests = column.get("tests")
127
+ return [str(test) for test in tests if isinstance(test, str)] if isinstance(tests, list) else []
128
+
129
+
130
+ def _column_line(column: dict[str, Any], variant_shapes: set[str]) -> str:
131
+ name = _format_value(column.get("name"))
132
+ column_type = _format_value(column.get("type"))
133
+ tests = _column_tests(column)
134
+ attributes: list[str] = []
135
+ if "not_null" in tests:
136
+ attributes.append("required")
137
+ if "unique" in tests:
138
+ attributes.append("unique")
139
+ extra_tests = [test for test in tests if test not in {"not_null", "unique"}]
140
+ if extra_tests:
141
+ attributes.append("tests: " + ", ".join(extra_tests))
142
+ if column.get("type") == "variant":
143
+ attributes.append("variant shaped" if name in variant_shapes else "variant unshaped")
144
+ if column.get("format"):
145
+ attributes.append("format " + _format_value(column.get("format")))
146
+ description = column.get("description")
147
+ suffix = f" - {_truncate(description, 140)}" if isinstance(description, str) and description else ""
148
+ return f" - {name}: {column_type}; {_join(attributes)}{suffix}"
149
+
150
+
151
+ def _variant_rule_lines(spec_config: dict[str, Any]) -> list[str]:
152
+ rules = spec_config.get("rules")
153
+ if not isinstance(rules, list):
154
+ return []
155
+ lines: list[str] = []
156
+ for rule in rules:
157
+ if not isinstance(rule, dict) or rule.get("type") != "variant_shape":
158
+ continue
159
+ field = rule.get("field", rule.get("column"))
160
+ if not isinstance(field, str) or not field:
161
+ field = "unknown"
162
+ roots = rule.get("allowed_root_keys")
163
+ root_values = [str(value) for value in roots if isinstance(value, str)] if isinstance(roots, list) else []
164
+ paths = rule.get("paths")
165
+ path_count = len(paths) if isinstance(paths, list) else 0
166
+ required_count = (
167
+ len([path for path in paths if isinstance(path, dict) and path.get("required") is True])
168
+ if isinstance(paths, list)
169
+ else 0
170
+ )
171
+ lines.append(
172
+ f" - {field}: roots {_join(root_values)}; paths {path_count}; required_paths {required_count}"
173
+ )
174
+ return lines
175
+
176
+
177
+ def _ordered_record_fields(columns: list[dict[str, Any]], record: dict[str, Any]) -> list[str]:
178
+ ordered = [
179
+ str(column.get("name"))
180
+ for column in columns
181
+ if isinstance(column.get("name"), str) and column.get("name") in record
182
+ ]
183
+ extras = sorted(str(key) for key in record if str(key) not in ordered)
184
+ return ordered + extras
185
+
186
+
187
+ def _sample_key(columns: list[dict[str, Any]], records: list[Any]) -> str:
188
+ if not records or not isinstance(records[0], dict):
189
+ return "none"
190
+ first = records[0]
191
+ preferred: list[str] = []
192
+ for test_name in ("unique", "not_null"):
193
+ preferred.extend(
194
+ str(column.get("name"))
195
+ for column in columns
196
+ if isinstance(column.get("name"), str) and test_name in _column_tests(column)
197
+ )
198
+ preferred.extend(str(column.get("name")) for column in columns if isinstance(column.get("name"), str))
199
+ for field in preferred:
200
+ if field in first and not isinstance(first[field], (dict, list)):
201
+ return f"{field}={_truncate(first[field])}"
202
+ return "none"
203
+
204
+
62
205
  def _text_status(workspace: Path, filename: str) -> str:
63
206
  path = workspace / filename
64
207
  if not path.exists():
@@ -82,34 +225,83 @@ def workspace_summary(
82
225
  variants = [str(column.get("name")) for column in columns if column.get("type") == "variant"]
83
226
  variant_shapes = _variant_shape_fields(spec_config)
84
227
  records = sample_records.get("records")
85
- record_count = len(records) if isinstance(records, list) else 0
228
+ record_list = records if isinstance(records, list) else []
229
+ record_count = len(record_list)
230
+ first_record = record_list[0] if record_list and isinstance(record_list[0], dict) else {}
86
231
  file_rules = spec_config.get("file_rules")
87
232
  file_format = file_rules.get("file_format") if isinstance(file_rules, dict) else None
88
- file_type = file_format.get("file_type") if isinstance(file_format, dict) else "unknown"
233
+ file_format = file_format if isinstance(file_format, dict) else {}
234
+ guest_access = spec_config.get("guest_access")
235
+ guest_access = guest_access if isinstance(guest_access, dict) else {}
236
+ attachment_policy = spec_config.get("attachment_policy")
237
+ attachment_policy = attachment_policy if isinstance(attachment_policy, dict) else {}
238
+ variant_rule_lines = _variant_rule_lines(spec_config)
89
239
 
90
240
  lines = [
91
241
  f"workspace: {workspace}",
92
242
  f"spec: {core.get('spec_name', 'unknown')} ({core.get('spec_alias', 'no alias')})",
93
- f"owner_role: {core.get('owner_role', 'unknown')}",
94
- f"columns: {len(columns)} total, {len(required)} required, {len(variants)} variant",
95
- "required_fields: " + (", ".join(required) if required else "none"),
96
- "variant_fields: "
97
- + (
98
- ", ".join(
99
- f"{name}{' shaped' if name in variant_shapes else ' unshaped'}" for name in variants
100
- )
101
- if variants
102
- else "none"
103
- ),
104
- f"sample_records: {record_count}",
105
- f"file_type: {file_type}",
106
- f"attachments: {_attachment_summary(spec_config)}",
107
- f"guest_access: {_guest_access_summary(spec_config)}",
108
- "notes: "
109
- + "; ".join(
110
- _text_status(workspace, filename)
111
- for filename in ("brief.md", "decisions.md", "questions.md", "review.md")
112
- ),
113
- f"check: {len(result.errors)} error(s), {len(result.warnings)} warning(s)",
243
+ "",
244
+ "core:",
245
+ f" spec_name: {_format_value(core.get('spec_name'))}",
246
+ f" spec_alias: {_format_value(core.get('spec_alias'), default='none')}",
247
+ f" owner_role: {_format_value(core.get('owner_role'))}",
248
+ f" published: {_format_value(core.get('is_published'))}",
249
+ f" archived: {_format_value(core.get('is_archived'))}",
250
+ f" description: {_truncate(core.get('description')) or 'none'}",
251
+ "",
252
+ "file_rules:",
253
+ f" file_type: {_format_value(file_format.get('file_type'))}",
254
+ f" parse_header: {_format_value(file_format.get('parse_header'))}",
255
+ f" save_header: {_format_value(file_format.get('save_header'))}",
256
+ f" field_delimiter: {_format_literal(file_format.get('field_delimiter'))}",
257
+ f" record_delimiter: {_format_literal(file_format.get('record_delimiter'))}",
258
+ f" encoding: {_format_value(file_format.get('encoding'))}",
259
+ "",
260
+ "attachments:",
261
+ f" summary: {_attachment_summary(spec_config)}",
262
+ f" enabled: {_format_value(attachment_policy.get('attachments_enabled'))}",
263
+ f" required: {_format_value(attachment_policy.get('attachment_required'))}",
264
+ "",
265
+ "guest_access:",
266
+ f" summary: {_guest_access_summary(spec_config)}",
267
+ f" isolated_directories_enabled: {_format_value(guest_access.get('isolated_directories_enabled'))}",
268
+ f" public_folder_enabled: {_format_value((guest_access.get('public_folder') or {}).get('enabled') if isinstance(guest_access.get('public_folder'), dict) else None)}",
269
+ f" enabled_subfolders: {_join(_enabled_guest_subfolders(guest_access))}",
270
+ f" guest_roles: {_join(_guest_role_lines(guest_access))}",
271
+ "",
272
+ "column_rules:",
273
+ f" total: {len(columns)}",
274
+ f" required_fields: {_join(required)}",
275
+ f" variant_fields: {_join([f'{name} shaped' if name in variant_shapes else f'{name} unshaped' for name in variants])}",
276
+ " columns:",
114
277
  ]
278
+ lines.extend(_column_line(column, variant_shapes) for column in columns)
279
+ lines.extend(
280
+ [
281
+ " variant_shape_rules:",
282
+ *(variant_rule_lines if variant_rule_lines else [" - none"]),
283
+ "",
284
+ "samples:",
285
+ f" spec_name: {_format_value(sample_records.get('spec_name'))}",
286
+ f" filename: {_format_value(sample_records.get('filename'))}",
287
+ f" records: {record_count}",
288
+ f" first_record_key: {_sample_key(columns, record_list)}",
289
+ f" first_record_fields: {_join(_ordered_record_fields(columns, first_record))}",
290
+ "",
291
+ "notes:",
292
+ *(
293
+ f" {_text_status(workspace, filename)}"
294
+ for filename in ("brief.md", "decisions.md", "questions.md", "review.md")
295
+ ),
296
+ "",
297
+ "check:",
298
+ f" errors: {len(result.errors)}",
299
+ f" warnings: {len(result.warnings)}",
300
+ ]
301
+ )
302
+ if result.findings:
303
+ lines.append(" findings:")
304
+ lines.extend(
305
+ f" - {finding.level}: {finding.path}: {finding.message}" for finding in result.findings
306
+ )
115
307
  return "\n".join(lines)
package/src/mcp.mjs CHANGED
@@ -44,10 +44,10 @@ export function handleMcpRequest(message) {
44
44
  },
45
45
  serverInfo: {
46
46
  name: "airlock",
47
- version: "0.1.0",
47
+ version: "0.1.2",
48
48
  },
49
49
  instructions:
50
- "Airlock MCP helps agents build and use 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. 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 blank specs repo and choose the first Airlock path.",
87
+ description: "Bootstrap a Git-backed specs repo and choose the first Airlock 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 and using Airlock specs in a blank specs repo.",
106
+ description: "Start building and using Airlock specs in a Git-backed specs repo.",
107
107
  messages: [
108
108
  {
109
109
  role: "user",
package/src/text.mjs CHANGED
@@ -21,18 +21,40 @@ export function airlockPrompt(project) {
21
21
  const repoName = specsRepoName(project);
22
22
  return `I want to use Airlock MCP to start working with Airlock specs for ${repoName}.
23
23
 
24
- Set up this project as an Airlock specs repo. Use Airlock MCP
25
- spec-building when we need to draft or revise specs. Welcome me,
26
- help me think through real Airlock use cases, and ask only for the missing
27
- decisions. Do not create the first workspace until I choose a path.`;
24
+ Set up this project as an Airlock specs repo. If this project is not already a
25
+ Git repo, recommend storing it in version control, preferably GitHub if that is
26
+ available. If you are creating the repo for me, ask where the ${repoName}
27
+ directory should live before making it, then offer to initialize git and create
28
+ or push a GitHub repo.
29
+
30
+ Welcome me by asking what process I want to improve. Explain that Airlock works
31
+ best when we can identify the loop around that process: what information comes
32
+ in, what context helps us understand it, what decision needs to be made, and
33
+ what action happens after the decision. Information may come from apps, files,
34
+ forms, people,
35
+ emails, calls, mail, websites, APIs, data feeds, or physical events. Actions
36
+ may go back through those same places. Ask whether I already have artifacts:
37
+ CSV or Excel files, JSON samples, API docs, schemas, forms, screenshots, PDFs,
38
+ exports, message examples, or other content people already use. Treat a small
39
+ real sample as stronger evidence than a long explanation, and remind me to
40
+ redact secrets.
41
+
42
+ When useful, check the reusable airlock-specs library for starting points,
43
+ patterns, and ideas, but do not assume those library specs match current
44
+ third-party systems. Prefer current API docs, real exports, samples, and other
45
+ artifacts when they conflict with a library shape.
46
+
47
+ 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.`;
28
49
  }
29
50
 
30
51
  export function nextSteps(project) {
31
52
  const repoName = specsRepoName(project);
32
53
  return `Next:
33
54
  1. Open Codex.
34
- 2. Create a new blank project named ${repoName}.
35
- 3. Ask Codex:
55
+ 2. Create or open a Git-backed specs repo named ${repoName}. GitHub is the recommended default when available.
56
+ 3. If Codex is creating it, ask Codex where the ${repoName} directory should live before it makes files.
57
+ 4. Ask Codex:
36
58
 
37
59
  ${airlockPrompt(project)
38
60
  .split("\n")
@@ -40,47 +62,68 @@ ${airlockPrompt(project)
40
62
  .join("\n")}
41
63
 
42
64
  Airlock MCP will offer:
43
- - spec-building with the bundled workbench
44
- - spec use and improvement loops with Airlock Star
45
- - guidance for pulling and pushing governed data through specs
46
- - OODA brainstorming for possible specs
47
- - a blank workspace for a known process
48
- - a posts feedback loop for shared human/agent feedback`;
65
+ - process discovery before choosing a spec pattern
66
+ - spec design with the bundled workbench
67
+ - Airlock operating patterns for OODA loops and separation of duties
68
+ - observe specs for controlled interface ingestion
69
+ - orient specs for proposals, context, scoring, or exception queues
70
+ - decision specs and action specs for governed follow-through
71
+ - artifact-grounded drafts from CSV, Excel, JSON, API docs, schemas, forms, screenshots, PDFs, or exports
72
+ - airlock-specs library patterns as starting points, checked against current artifacts`;
49
73
  }
50
74
 
51
75
  export function gettingStartedText(project) {
52
76
  return `# Airlock MCP
53
77
 
54
78
  Airlock MCP is the single installed interface for AI agents working with
55
- Airlock. It helps a person and their agent build specs, pull and push governed data
56
- through specs, and improve Airlock workflows from real use cases.
79
+ Airlock. It helps a person and their agent improve processes by designing
80
+ specs, using specs for governed data movement, and planning OODA loops that
81
+ can be assisted by people or agents.
57
82
 
58
- The Airlock MCP spec-building workbench drafts, checks, revises, imports,
59
- clones, and prepares specs for installed Airlock validation.
83
+ Airlock MCP gives agents two kinds of Airlock expertise:
60
84
 
61
- Airlock Star is the use-and-improve capability inside Airlock MCP. Use it when
62
- someone wants to pull or push governed data through specs, exercise real
63
- Airlock workflows, inspect outputs, or turn field experience into spec
64
- improvements.
85
+ 1. Spec design: draft, check, revise, import, clone, and prepare specs for
86
+ installed Airlock validation.
87
+ 2. Airlock operating patterns: use specs to organize observations, orientation,
88
+ governed decisions, controlled actions, separation of duties, and feedback
89
+ loops.
65
90
 
66
- Start in a blank project specs repo such as ${specsRepoName(project)}. Do not
67
- work inside the Airlock MCP implementation repo unless you are changing the
68
- tools themselves.
91
+ Start in a Git-backed specs repo such as ${specsRepoName(project)}. GitHub is
92
+ the recommended default when the user has it set up, but any normal repository
93
+ works. If Codex is creating the repo, ask where the directory should live before
94
+ making files. Do not work inside the Airlock MCP implementation repo unless you
95
+ are changing the tools themselves.
69
96
 
70
- Use this prompt in the blank specs repo:
97
+ Use this prompt in the specs repo:
71
98
 
72
99
  ${airlockPrompt(project)}
73
100
 
74
- After bootstrap, choose the next useful path:
101
+ First ask: What process do you want to improve?
75
102
 
76
- 1. Brainstorm possible specs using the OODA loop.
77
- 2. Start from a known process and create a blank workspace.
78
- 3. Create a posts feedback loop for humans and agents to submit requests,
79
- observations, and responses.
80
- 4. Use Airlock Star with an installed Airlock app to validate specs, load data,
81
- read outputs, plan push/pull workflows, and capture improvements.
103
+ Airlock works best when we can identify the loop around a process:
82
104
 
83
- Create posts only when the user chooses the feedback-loop path.`;
105
+ 1. Observe: what information comes in.
106
+ 2. Orient: what context helps people or agents understand it.
107
+ 3. Decide: what choice needs to be governed.
108
+ 4. Act: what happens after the decision.
109
+
110
+ Information may come from apps, files, forms, people, emails, calls, mail,
111
+ websites, APIs, data feeds, or physical events. Actions may go back through
112
+ those same places. Airlock calls these places interfaces: where the process
113
+ observes from or acts through.
114
+
115
+ If you already have artifacts, attach or point Codex at them: CSV or Excel
116
+ files, JSON samples, API docs, schemas, forms, screenshots, PDFs, exports,
117
+ message examples, or other defined content people already use. A small real
118
+ sample is often better than a long explanation. Redact secrets before sharing.
119
+
120
+ Airlock MCP can also use the reusable airlock-specs library for starting
121
+ points, patterns, and ideas. Library specs are not guaranteed to match the
122
+ current shape of any third-party system. Prefer current API docs, real exports,
123
+ samples, and other artifacts when they conflict with the library.
124
+
125
+ 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.`;
84
127
  }
85
128
 
86
129
  export function helpText() {
@@ -103,6 +146,7 @@ Options:
103
146
 
104
147
  Airlock MCP is the single installed interface for agents working with Airlock.
105
148
  Spec building is bundled inside that experience.
106
- Airlock Star is the use-and-improve capability inside that experience.
149
+ Airlock operating patterns help connect specs into OODA loops, separation of
150
+ duties, governed decisions, controlled actions, and feedback loops.
107
151
  `;
108
152
  }
package/src/workbench.mjs CHANGED
@@ -31,7 +31,7 @@ export const WORKBENCH_TOOLS = [
31
31
  },
32
32
  {
33
33
  name: "airlock_init_repo",
34
- description: "Bootstrap a specs repo with AGENTS.md, the Airlock MCP skill, and workspaces/.",
34
+ description: "Bootstrap a Git-backed specs repo with AGENTS.md, the Airlock MCP skill, and workspaces/.",
35
35
  inputSchema: objectSchema({
36
36
  path: {
37
37
  type: "string",