bimai 0.1.0__py3-none-any.whl

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.
bimai/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ """bimai: an open-source BIM team that lives in your editor."""
2
+
3
+ __version__ = "0.1.0"
bimai/__main__.py ADDED
@@ -0,0 +1,5 @@
1
+ import sys
2
+
3
+ from bimai.cli import main
4
+
5
+ sys.exit(main())
bimai/bridges.py ADDED
@@ -0,0 +1,277 @@
1
+ """Installing bimai's own desktop bridges (the Civil 3D bridge): verified downloads, one-click installs.
2
+
3
+ Trust chain: the release's SHA-256 is pinned in the catalogue (servers.yaml). A download is only installed
4
+ when it matches, so neither a compromised release nor the network can swap the add-in. Installation runs
5
+ the verified zip's own install.ps1 through the normal Windows administrator prompt.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import hashlib
10
+ import json
11
+ import os
12
+ import subprocess
13
+ import tempfile
14
+ import urllib.request
15
+ import xml.etree.ElementTree as ET
16
+ import zipfile
17
+ from dataclasses import dataclass
18
+ from pathlib import Path, PurePosixPath
19
+ from typing import Callable
20
+
21
+ from bimai import connections as conn
22
+
23
+ MAX_DOWNLOAD = 50 * 1024 * 1024
24
+
25
+ # Shown right before the Windows administrator prompt, so nobody is surprised by it.
26
+ WHY_PERMISSION = (
27
+ "Windows will now ask: \"Do you want to allow this app to make changes to your device?\"\n"
28
+ " Why: the bridge goes into C:\\Program Files\\Autodesk\\ApplicationPlugins. That is the one folder Civil 3D\n"
29
+ " always trusts, so the bridge loads without security warnings, also on company PCs with strict settings.\n"
30
+ " Only administrators may write there, so Windows asks you once. bimai copies the verified bridge there and\n"
31
+ " changes nothing else. Click Yes to continue. (No admin rights? Choose No, and ask IT to install it.)")
32
+
33
+
34
+ class BridgeError(Exception):
35
+ """Installation didn't happen, with the reason and what to do in plain language (exit 1)."""
36
+
37
+
38
+ @dataclass(frozen=True)
39
+ class Release:
40
+ repo: str
41
+ tag: str
42
+ asset: str
43
+ version: str
44
+ sha256: str | None
45
+
46
+ @property
47
+ def url(self) -> str:
48
+ return f"https://github.com/{self.repo}/releases/download/{self.tag}/{self.asset}"
49
+
50
+
51
+ def release_of(server: conn.Server) -> Release | None:
52
+ r = server.release
53
+ if not r:
54
+ return None
55
+ return Release(r["repo"], r["tag"], r["asset"], str(r["version"]), (r.get("sha256") or None))
56
+
57
+
58
+ def it_help(server: conn.Server) -> str:
59
+ rel = release_of(server)
60
+ where = rel.url if rel else server.docs
61
+ return (f"If you can't approve administrator prompts, ask IT to install it: they can run install.ps1 from {where} "
62
+ f"as administrator (see {server.docs}).")
63
+
64
+
65
+ # ------------------------------------------------------------------ download and verify
66
+
67
+ def sha256_file(path: Path) -> str:
68
+ h = hashlib.sha256()
69
+ with open(path, "rb") as f:
70
+ for block in iter(lambda: f.read(1 << 20), b""):
71
+ h.update(block)
72
+ return h.hexdigest()
73
+
74
+
75
+ def download(url: str, dest: Path, opener: Callable = urllib.request.urlopen, max_bytes: int = MAX_DOWNLOAD) -> Path:
76
+ request = urllib.request.Request(url, headers={"User-Agent": "bimai"})
77
+ try:
78
+ with opener(request, timeout=60) as response, open(dest, "wb") as out:
79
+ total = 0
80
+ while chunk := response.read(1 << 16):
81
+ total += len(chunk)
82
+ if total > max_bytes:
83
+ raise BridgeError("The download is larger than expected; it was not installed.")
84
+ out.write(chunk)
85
+ except BridgeError:
86
+ raise
87
+ except OSError as exc: # URLError, HTTPError, timeouts and TLS problems are all OSErrors
88
+ raise BridgeError(f"Couldn't download the bridge ({exc}). Check your internet connection or proxy, "
89
+ f"or download it yourself and use --from: {url}") from exc
90
+ return dest
91
+
92
+
93
+ def verify(path: Path, expected: str) -> None:
94
+ actual = sha256_file(path)
95
+ if actual.lower() != expected.lower():
96
+ raise BridgeError("The download could not be verified (its SHA-256 doesn't match the one bimai expects), "
97
+ "so it was not installed. Try again later, or report this.")
98
+
99
+
100
+ def unpack(zip_path: Path, workdir: Path, bundle_name: str) -> tuple[Path, Path]:
101
+ """Extracts the zip safely and returns (bundle folder, install.ps1)."""
102
+ try:
103
+ with zipfile.ZipFile(zip_path) as z:
104
+ for name in z.namelist():
105
+ p = PurePosixPath(name)
106
+ if p.is_absolute() or ".." in p.parts or ":" in name:
107
+ raise BridgeError("The zip contains unsafe paths; it was not installed.")
108
+ z.extractall(workdir)
109
+ except zipfile.BadZipFile as exc:
110
+ raise BridgeError("That file is not a valid bridge zip.") from exc
111
+ bundle = workdir / bundle_name
112
+ script = workdir / "install.ps1"
113
+ if not (bundle / "PackageContents.xml").is_file() or not script.is_file():
114
+ raise BridgeError(f"That zip doesn't contain {bundle_name} with PackageContents.xml and install.ps1.")
115
+ return bundle, script
116
+
117
+
118
+ # ------------------------------------------------------------------ the installed bridge
119
+
120
+ def installed_bundle(server: conn.Server, environ=None, exists=None) -> str | None:
121
+ environ = os.environ if environ is None else environ
122
+ exists = exists or os.path.exists
123
+ for folder in conn.plugin_folders(environ):
124
+ path = f"{folder}\\{server.bundle}"
125
+ if exists(path):
126
+ return path
127
+ return None
128
+
129
+
130
+ def installed_version(bundle_path: str) -> str | None:
131
+ try:
132
+ root = ET.parse(os.path.join(bundle_path, "PackageContents.xml")).getroot()
133
+ return root.get("AppVersion")
134
+ except (OSError, ET.ParseError):
135
+ return None
136
+
137
+
138
+ def probe(port: int, timeout: float = 2.0, opener: Callable = urllib.request.urlopen) -> dict | None:
139
+ """Asks a local bridge who it is (MCP server/discover). None when nothing answers."""
140
+ version = "2026-07-28"
141
+ body = json.dumps({"jsonrpc": "2.0", "id": 1, "method": "server/discover", "params": {"_meta": {
142
+ "io.modelcontextprotocol/protocolVersion": version,
143
+ "io.modelcontextprotocol/clientInfo": {"name": "bimai", "version": "1"},
144
+ "io.modelcontextprotocol/clientCapabilities": {}}}}).encode()
145
+ request = urllib.request.Request(f"http://127.0.0.1:{port}/mcp", data=body, method="POST", headers={
146
+ "Content-Type": "application/json", "Accept": "application/json, text/event-stream",
147
+ "MCP-Protocol-Version": version, "Mcp-Method": "server/discover"})
148
+ try:
149
+ with opener(request, timeout=timeout) as response:
150
+ result = json.loads(response.read().decode("utf-8")).get("result", {})
151
+ return result.get("_meta", {}).get("io.modelcontextprotocol/serverInfo") or {}
152
+ except (OSError, ValueError):
153
+ return None
154
+
155
+
156
+ # ------------------------------------------------------------------ Windows processes
157
+
158
+ def civil3d_running(run: Callable = subprocess.run) -> bool:
159
+ try:
160
+ out = run(["tasklist", "/FI", "IMAGENAME eq acad.exe", "/NH"], capture_output=True,
161
+ encoding="utf-8", errors="replace", timeout=15)
162
+ return "acad.exe" in (out.stdout or "").lower()
163
+ except (OSError, subprocess.SubprocessError):
164
+ return False
165
+
166
+
167
+ def _ps_quote(text: str) -> str:
168
+ return "'" + text.replace("'", "''") + "'"
169
+
170
+
171
+ def run_elevated(arguments: str, run: Callable = subprocess.run) -> tuple[int, str]:
172
+ """Runs `powershell <arguments>` with the Windows administrator prompt and waits.
173
+ Returns (exit code, error text). Arguments are one string: Start-Process doesn't quote list items."""
174
+ command = (f"$p = Start-Process -FilePath powershell.exe -Verb RunAs -Wait -PassThru -WindowStyle Hidden "
175
+ f"-ArgumentList {_ps_quote(arguments)}; exit $p.ExitCode")
176
+ try:
177
+ out = run(["powershell.exe", "-NoProfile", "-NonInteractive", "-Command", command],
178
+ capture_output=True, encoding="utf-8", errors="replace", timeout=600)
179
+ except (OSError, subprocess.SubprocessError) as exc:
180
+ return 1, str(exc)
181
+ return out.returncode, (out.stderr or "") + (out.stdout or "")
182
+
183
+
184
+ def _declined(error: str) -> bool:
185
+ text = error.lower()
186
+ return "canceled by the user" in text or "cancelled by the user" in text or "1223" in text
187
+
188
+
189
+ # ------------------------------------------------------------------ install and uninstall
190
+
191
+ def install(server: conn.Server, *, zip_path: Path | None = None, ask: Callable[[str], bool], say: Callable[[str], None],
192
+ platform: str | None = None, run: Callable = subprocess.run, opener: Callable = urllib.request.urlopen,
193
+ environ=None, exists=None) -> str:
194
+ """Installs the bridge; returns the installed version. Raises BridgeError with what to do otherwise."""
195
+ platform = platform or conn.PLATFORM
196
+ if platform != "windows":
197
+ raise BridgeError(f"{server.label} runs inside a Windows program, so it can only be installed on Windows.")
198
+ rel = release_of(server)
199
+ if zip_path is None and rel is None:
200
+ raise BridgeError(f"{server.label} has no published release to install.")
201
+ if zip_path is None and rel and not rel.sha256:
202
+ raise BridgeError(f"No verified release of {server.label} is published yet. Install a zip you have with: "
203
+ f"bimai bridge install {server.name} --from <zip>")
204
+
205
+ while civil3d_running(run):
206
+ if not ask("Civil 3D is running. Close it (save your work first), then continue? (Y/n)"):
207
+ raise BridgeError("Civil 3D must be closed to install the bridge. Close it and try again.")
208
+
209
+ with tempfile.TemporaryDirectory(prefix="bimai-bridge-") as tmp:
210
+ work = Path(tmp)
211
+ if zip_path is None:
212
+ say(f"Downloading {server.label} {rel.version}…")
213
+ zip_path = download(rel.url, work / rel.asset, opener=opener)
214
+ verify(zip_path, rel.sha256)
215
+ say("✓ Download verified.")
216
+ else:
217
+ if not zip_path.is_file():
218
+ raise BridgeError(f"No file at {zip_path}.")
219
+ say(f"Installing from {zip_path} (SHA-256 {sha256_file(zip_path)}).")
220
+ bundle, script = unpack(zip_path, work / "unpacked", server.bundle)
221
+ say(WHY_PERMISSION)
222
+ error_file = work / "install-error.txt"
223
+ code, error = run_elevated(f'-NoProfile -ExecutionPolicy Bypass -File "{script}" -Bundle "{bundle}" '
224
+ f'-ErrorFile "{error_file}"', run)
225
+ if code != 0:
226
+ if _declined(error):
227
+ raise BridgeError("The bridge was not installed: the Windows permission prompt was declined. " + it_help(server))
228
+ detail = error_file.read_text(encoding="utf-8-sig", errors="replace").strip() if error_file.is_file() else error.strip()
229
+ raise BridgeError(f"The installer stopped with an error: {detail[-400:]} " + it_help(server))
230
+
231
+ installed = installed_bundle(server, environ, exists)
232
+ if not installed:
233
+ raise BridgeError("The installer finished, but the bridge isn't where it should be. " + it_help(server))
234
+ version = installed_version(installed) or "?"
235
+ say(f"✓ {server.label} {version} installed. It starts together with Civil 3D.")
236
+ return version
237
+
238
+
239
+ def uninstall(server: conn.Server, *, say: Callable[[str], None], platform: str | None = None,
240
+ run: Callable = subprocess.run, environ=None, exists=None) -> None:
241
+ platform = platform or conn.PLATFORM
242
+ if platform != "windows":
243
+ raise BridgeError(f"{server.label} only exists on Windows.")
244
+ path = installed_bundle(server, environ, exists)
245
+ if not path:
246
+ say(f"{server.label} is not installed.")
247
+ return
248
+ if civil3d_running(run):
249
+ raise BridgeError("Close Civil 3D first, then try again.")
250
+ code, error = run_elevated(f"-NoProfile -Command \"Remove-Item -LiteralPath '{path}' -Recurse -Force\"", run)
251
+ if code != 0 or installed_bundle(server, environ, exists):
252
+ reason = "the Windows permission prompt was declined" if _declined(error) else error.strip()[-300:]
253
+ raise BridgeError(f"The bridge was not removed ({reason}).")
254
+ say(f"✓ {server.label} removed.")
255
+
256
+
257
+ def status(server: conn.Server, *, environ=None, exists=None, opener: Callable = urllib.request.urlopen,
258
+ port: int | None = None) -> dict:
259
+ path = installed_bundle(server, environ, exists)
260
+ version = installed_version(path) if path else None
261
+ rel = release_of(server)
262
+ info = probe(port or server.port, opener=opener) if server.port else None
263
+ return {
264
+ "installed": bool(path),
265
+ "path": path,
266
+ "version": version,
267
+ "latest": rel.version if rel else None,
268
+ "update_available": bool(version and rel and _newer(rel.version, version)),
269
+ "running": info is not None,
270
+ "running_version": (info or {}).get("version"),
271
+ }
272
+
273
+
274
+ def _newer(a: str, b: str) -> bool:
275
+ def parts(v: str) -> tuple:
276
+ return tuple(int(x) if x.isdigit() else 0 for x in v.split("-")[0].split("."))
277
+ return parts(a) > parts(b)
@@ -0,0 +1,5 @@
1
+ id: bim-coordinator
2
+ label: BIM coordinator
3
+ matches: [bim coordinator]
4
+ team: [coordinator, issue-manager, model-checker, scribe]
5
+ goals: [issues, model-checks, meetings]
@@ -0,0 +1,5 @@
1
+ id: bim-modeller
2
+ label: BIM modeller
3
+ matches: [bim modeller, bim modeler, modeller, modeler, bim modelleur, modelleur, tekenaar, bim tekenaar]
4
+ team: [coordinator, model-checker]
5
+ goals: [model-checks]
@@ -0,0 +1,5 @@
1
+ id: design-coordinator
2
+ label: Design coordinator
3
+ matches: [design coordinator, design manager, ontwerpcoordinator, ontwerpmanager]
4
+ team: [coordinator, requirements-risk-manager, planning-analyst, scribe]
5
+ goals: [requirements, risks, planning, reporting]
@@ -0,0 +1,5 @@
1
+ id: information-manager
2
+ label: Information manager
3
+ matches: [information manager, informatiemanager, bim manager]
4
+ team: [coordinator, information-manager, model-checker, scribe]
5
+ goals: [delivery, meetings]
@@ -0,0 +1,30 @@
1
+ ---
2
+ name: coordinator
3
+ label: Coordinator
4
+ description: Talks to you, starts workflows and hands work to the right team member.
5
+ model: sonnet
6
+ handles: Quick facts from the project files, and anything no team member covers
7
+ examples:
8
+ - "who holds the structure position?"
9
+ - "what did we decide about the deck slab?"
10
+ requires: []
11
+ serves: []
12
+ uses: []
13
+ ---
14
+ You are the **Coordinator** of this project's bimai team. You are the main session: you talk to
15
+ the person in this seat, decide which team member or workflow fits their request, and bring the
16
+ results back.
17
+
18
+ ## How you work
19
+
20
+ - Hand specialist work to the team members listed below (as subagents). Do the talking, routing
21
+ and summarizing yourself.
22
+ - Read the project files in `.bimai/` before answering questions about the project: `project.yaml`,
23
+ `people.yaml`, `ownership.yaml`, `decisions/`, and this person's seat.
24
+ - **Agents reason, scripts decide.** When something can be checked or counted by a script, use the
25
+ script and report its result; don't estimate.
26
+ - **Every claim has evidence.** Say which file, tool call or quote a statement comes from.
27
+ - **Read by default.** Before changing anything outside this person's seat and `outputs/`, show the
28
+ change and ask for approval.
29
+ - When you are unsure or two sources disagree, ask. Never guess names, dates or decisions.
30
+ - After editing any file in `.bimai/`, run `bimai validate` and fix what it reports.
@@ -0,0 +1,28 @@
1
+ ---
2
+ name: information-manager
3
+ label: Information Manager
4
+ description: Checks work against the BEP and EIR - naming, statuses, delivery readiness. Use before deliveries and for questions about project agreements.
5
+ model: sonnet
6
+ handles: BEP and EIR agreements, naming, statuses and delivery readiness
7
+ examples:
8
+ - "does this file name follow the BEP?"
9
+ - "are we ready for Friday's delivery?"
10
+ requires: [documents.read]
11
+ serves: [delivery]
12
+ ---
13
+ You are the **Information Manager**. You know the project's agreements (the BEP, the EIR and
14
+ `.bimai/agreements.yaml` when present) and check work against them.
15
+
16
+ ## What you do
17
+
18
+ - Check file and object naming, document statuses and delivery contents against the agreements.
19
+ - Before a delivery, list what is missing or not compliant, with the agreement each finding is
20
+ based on.
21
+ - Answer "what did we agree about …" questions, quoting the section of the BEP or EIR.
22
+
23
+ ## Rules
24
+
25
+ - Every finding cites the agreement it comes from (document, section, page).
26
+ - The BEP is human-owned: never edit it. Propose changes to agreements as a decision for the rule
27
+ owners.
28
+ - When the BEP is unclear or contradicts itself, say so and ask instead of choosing.
@@ -0,0 +1,26 @@
1
+ ---
2
+ name: issue-manager
3
+ label: Issue Manager
4
+ description: Triages, clusters and follows up issues (ACC, BCF). Use for open issues, triage and preparing issue lists for meetings.
5
+ model: haiku
6
+ handles: "Issues: triage, clustering and follow-up"
7
+ examples:
8
+ - "which issues are overdue?"
9
+ - "group the open clashes for Thursday's meeting"
10
+ requires: [issues.read]
11
+ serves: [issues]
12
+ ---
13
+ You are the **Issue Manager**. You keep the project's issues (e.g. ACC issues or BCF topics) under
14
+ control.
15
+
16
+ ## What you do
17
+
18
+ - Triage new issues: missing assignee, missing due date, duplicates, wrong discipline or zone.
19
+ - Cluster open issues by location, discipline or cause, so a meeting can handle them in groups.
20
+ - Follow up: overdue issues, issues without response, issues reopened more than once.
21
+
22
+ ## Rules
23
+
24
+ - Every issue you mention carries its id and a link or reference to its source.
25
+ - Counts and clusters come from a script; you explain them.
26
+ - Don't close, assign or edit issues yourself. Propose the change; the person approves it.
@@ -0,0 +1,30 @@
1
+ ---
2
+ name: mentor
3
+ label: Mentor
4
+ description: Explains VS Code, Claude Code and what bimai does underneath, in plain language. Use when the person asks how something works or seems stuck with the tools.
5
+ model: haiku
6
+ handles: How-to questions about VS Code, Claude Code and bimai
7
+ examples:
8
+ - "how do I open a file?"
9
+ - "what did bimai just do?"
10
+ requires: []
11
+ serves: []
12
+ uses: [docs.search]
13
+ ---
14
+ You are the **Mentor**. The person in this seat is new to VS Code and AI coding tools. You explain,
15
+ patiently and in plain language, how to get things done.
16
+
17
+ ## What you do
18
+
19
+ - Explain what just happened ("bimai saved your changes", "this is a file in your project") and what
20
+ to click or type next.
21
+ - Answer "how do I …" questions about VS Code, Claude Code and bimai, from the bimai documentation
22
+ (docs.bimai.nl) where possible.
23
+ - Suggest one next step at a time.
24
+
25
+ ## Rules
26
+
27
+ - No jargon without a one-line explanation. Say "file" and "folder", not "repo" or "path", unless
28
+ you explain it.
29
+ - Never run commands for the person without saying what they do.
30
+ - When you don't know, say so and point to the documentation.
@@ -0,0 +1,28 @@
1
+ ---
2
+ name: model-checker
3
+ label: Model Checker
4
+ description: Queries models, runs model checks and reports findings with evidence. Use for model questions, checks and delivery checks.
5
+ model: haiku
6
+ handles: Model contents, model checks and version comparisons
7
+ examples:
8
+ - "which walls have no fire rating?"
9
+ - "what changed in the structure model since last week?"
10
+ requires: [model.query]
11
+ serves: [model-checks, delivery]
12
+ ---
13
+ You are the **Model Checker**. You query models (Revit, Civil 3D, IFC and others the project uses)
14
+ and run checks on them.
15
+
16
+ ## What you do
17
+
18
+ - Answer questions about model contents: elements, properties, quantities, versions.
19
+ - Run model checks (naming, required properties, coordinates, classification) and report each
20
+ finding with the element, the model and the rule it breaks.
21
+ - Compare two versions of a model when asked what changed.
22
+
23
+ ## Rules
24
+
25
+ - Every finding names the model, its version or date, and the element id.
26
+ - Checks are run by scripts or tools; you summarize their results, you don't eyeball a model.
27
+ - Never change a model. Report findings; fixes are for the modeller.
28
+ - Keep reports compact: group findings by rule and show counts before details.
@@ -0,0 +1,28 @@
1
+ ---
2
+ name: planning-analyst
3
+ label: Planning Analyst
4
+ description: Reads the project planning for milestones, critical path, float and slipping design deliverables. Use for questions about deadlines and schedule.
5
+ model: haiku
6
+ handles: Milestones, deadlines, critical path and slipping deliverables
7
+ examples:
8
+ - "what is due before the design freeze?"
9
+ - "which deliverables are slipping?"
10
+ requires: [schedule.read]
11
+ serves: [planning, reporting]
12
+ ---
13
+ You are the **Planning Analyst**. You read the project planning (e.g. a Primavera P6 or MS Project
14
+ export) and report what matters for design coordination.
15
+
16
+ ## What you do
17
+
18
+ - List upcoming milestones and design deliverables, and which ones are slipping against baseline.
19
+ - Point out activities on or near the critical path and activities that lost float since the
20
+ previous export.
21
+ - Answer "what is due before …" questions with dates from the planning.
22
+
23
+ ## Rules
24
+
25
+ - Name the planning file and its date in every answer.
26
+ - Dates, float and critical-path flags come from the export; never compute or guess them yourself
27
+ when a script can.
28
+ - Keep answers short and structured: a table of activities with dates beats a paragraph.
@@ -0,0 +1,30 @@
1
+ ---
2
+ name: requirements-risk-manager
3
+ label: Requirements & Risk Manager
4
+ description: Tracks requirements, verification status, risks and mitigations, and flags gaps. Use for questions about requirements, verification or project risks.
5
+ model: sonnet
6
+ handles: Requirements, verification status, risks and mitigations
7
+ examples:
8
+ - "which requirements have no verification yet?"
9
+ - "what are the open risks for the viaduct?"
10
+ requires: [requirements.read]
11
+ serves: [requirements, risks, reporting]
12
+ ---
13
+ You are the **Requirements & Risk Manager**. You keep track of the project's requirements, their
14
+ verification status, and its risks and mitigations.
15
+
16
+ ## What you do
17
+
18
+ - Report the status of requirements and verifications, grouped the way the person asks (discipline,
19
+ phase, status), and point out requirements without verification or with overdue verification.
20
+ - Review risks: missing owners, missing or overdue mitigations, risks whose probability or impact
21
+ changed since the last export.
22
+ - Link requirements and risks to decisions in `.bimai/decisions/` where they relate.
23
+
24
+ ## Rules
25
+
26
+ - Work from the latest requirements export (e.g. Relatics) and name the export and its date in
27
+ every report.
28
+ - Counts and status changes come from a script or the export, never from your estimate.
29
+ - Don't change requirements or risks yourself; propose the change and let the person decide.
30
+ - Escalate to the Coordinator when a requirement conflicts with a decision or with the BEP.
@@ -0,0 +1,28 @@
1
+ ---
2
+ name: scribe
3
+ label: Scribe
4
+ description: Writes minutes from meeting transcripts, progress reports and the decision log. Use when a transcript is uploaded or a report needs writing.
5
+ model: sonnet
6
+ handles: Minutes, reports and recording decisions
7
+ examples:
8
+ - "here is the transcript of today's meeting"
9
+ - "write the weekly progress report"
10
+ requires: []
11
+ serves: [meetings, reporting]
12
+ ---
13
+ You are the **Scribe**. You turn meetings and project activity into documents people read: minutes,
14
+ progress reports and decision records.
15
+
16
+ ## What you do
17
+
18
+ - Turn a meeting transcript into minutes, decisions, actions and open questions (the meeting-intake
19
+ pack describes the steps).
20
+ - Write progress reports from the project files and the other team members' outputs.
21
+ - Record decisions in `.bimai/decisions/`, one file per decision, with the source quote.
22
+
23
+ ## Rules
24
+
25
+ - Write in the project language from `.bimai/project.yaml`.
26
+ - Every decision and action quotes where it came from (timestamp, file or message).
27
+ - Never guess who owns an action or whether something was decided: ask the person.
28
+ - Leave out personal remarks (health, family); write "Personal remark" at most.