@specset/cli 0.4.0 → 0.5.1
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/dist/main.js +1595 -205
- package/package.json +1 -1
- package/skills/specset/SKILL.md +12 -81
- package/skills/specset-admin/SKILL.md +5 -9
- package/skills/specset-agent/SKILL.md +0 -2
- package/skills/specset-closeout/SKILL.md +2 -22
- package/skills/specset-projects/SKILL.md +4 -7
- package/skills/specset-rfis/SKILL.md +4 -32
- package/skills/specset-search/SKILL.md +6 -35
- package/skills/specset-submittals/SKILL.md +10 -60
- package/skills/specset-tools/SKILL.md +18 -3
package/package.json
CHANGED
package/skills/specset/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: specset
|
|
3
|
-
description: Core CLI for Specset — install or update the CLI, authenticate with a browser or device code, switch organizations, and run GraphQL with `specset api`. Start here for
|
|
3
|
+
description: Core CLI for Specset — install or update the CLI, authenticate with a browser or device code, switch organizations, and run GraphQL with `specset api`. Start here for CLI setup or raw GraphQL access, and whenever a specset command fails with auth or org errors.
|
|
4
4
|
allowed-tools: Bash Read AskUserQuestion
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -29,56 +29,12 @@ This is the core skill — setup and mechanics only. Domain workflows live in si
|
|
|
29
29
|
|
|
30
30
|
## First-Run Setup
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
Run this when the user installs or updates the skill/plugin, asks to get started with Specset, or when a command fails because the CLI is missing or unauthenticated. Every step is idempotent — skip any that's already satisfied.
|
|
33
33
|
|
|
34
|
-
1.
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
npm view @specset/cli version
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
If `specset` is missing or its version is older than the published version, update it and verify the result:
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
npm install -g @specset/cli@latest
|
|
45
|
-
specset --version
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
Requires Node.js 20+ with npm. If `npm` itself is missing, stop and ask the user to install Node.js (https://nodejs.org) first. Do not replace a source-linked development CLI when its version is newer than npm.
|
|
49
|
-
|
|
50
|
-
2. Check authentication with `specset auth status`. If not logged in, choose the login mode based on whether the user can see a browser opened by this environment.
|
|
51
|
-
|
|
52
|
-
**If a visible browser is unavailable** — including remote or in-app agent sessions, SSH, containers, and CI — use device authentication from the outset:
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
specset login --device
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
It prints a short code and a link (`https://<host>/device?code=XXXX-XXXX`). Show both to the user and ask them to open the link on any device and approve; the command completes on its own once they do. The code expires after 15 minutes — if it does, run the command again for a fresh one.
|
|
59
|
-
|
|
60
|
-
When a visible browser is available on the same machine, use the browser flow and tell the user to complete sign-in there while the command waits:
|
|
61
|
-
|
|
62
|
-
```bash
|
|
63
|
-
specset login
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
Login is interactive by design — never try to bypass it or handle credentials directly. Don't launch a login mid-task without telling the user what's happening.
|
|
67
|
-
|
|
68
|
-
3. Pick the active organization (required for org-scoped queries):
|
|
69
|
-
|
|
70
|
-
```bash
|
|
71
|
-
specset org list
|
|
72
|
-
specset org use <slug>
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
If the user belongs to exactly one org, select it; otherwise ask which to use.
|
|
76
|
-
|
|
77
|
-
4. Confirm everything is ready:
|
|
78
|
-
|
|
79
|
-
```bash
|
|
80
|
-
specset auth status
|
|
81
|
-
```
|
|
34
|
+
1. **Install or update the CLI** (Node.js 20+). Installing a skill/plugin does not upgrade the npm package. If `specset --version` is missing or older than `npm view @specset/cli version`, run `npm install -g @specset/cli@latest` (don't replace a source-linked development CLI whose version is newer than npm). After upgrading, refresh the skills with `specset skill install --target <claude|codex|chatgpt>`.
|
|
35
|
+
2. **Authenticate** — check with `specset auth status`. If not logged in: `specset login` when a visible browser is available on this machine (tell the user to complete sign-in there while the command waits); `specset login --device` otherwise (SSH, containers, CI, remote/in-app sessions). Device login prints a code and a link (`https://<host>/device?code=XXXX-XXXX`) — show both to the user; the command completes once they approve. Codes expire after 15 minutes; rerun for a fresh one.
|
|
36
|
+
3. **Pick the active organization** (required for org-scoped queries): `specset org list`, then `specset org use <slug>`. If the user belongs to exactly one org, select it; otherwise ask which to use.
|
|
37
|
+
4. **Confirm** with `specset auth status`.
|
|
82
38
|
|
|
83
39
|
Credentials persist across sessions in `~/.config/specset/config.yml` (mode 0600) — setup only needs to happen once per machine.
|
|
84
40
|
|
|
@@ -109,34 +65,17 @@ GQL
|
|
|
109
65
|
|
|
110
66
|
### Schema Discovery
|
|
111
67
|
|
|
112
|
-
|
|
68
|
+
The domain skills document the operations that matter for each workflow, but they are not exhaustive — when an operation or argument doesn't match, introspect rather than guess:
|
|
113
69
|
|
|
114
70
|
```bash
|
|
115
|
-
# Top-level queries
|
|
116
|
-
specset api --query '{ __schema { queryType { fields { name description } } } }'
|
|
117
|
-
|
|
118
|
-
# Fields on a specific type
|
|
119
71
|
specset api --query '{ __type(name: "Project") { fields { name type { name kind ofType { name } } } } }'
|
|
120
|
-
|
|
121
|
-
# Input object shape
|
|
122
|
-
specset api --query '{ __type(name: "CreateSubmittalInput") { inputFields { name type { name kind ofType { name } } } } }'
|
|
123
72
|
```
|
|
124
73
|
|
|
125
|
-
The
|
|
74
|
+
The same pattern works for input objects (`inputFields`) and the top-level surface (`{ __schema { queryType { fields { name description } } } }`).
|
|
126
75
|
|
|
127
76
|
## Agent Tools and MCP
|
|
128
77
|
|
|
129
|
-
Beyond raw GraphQL, the CLI exposes Specset's own retrieval tools — semantic and keyword search
|
|
130
|
-
|
|
131
|
-
- **As commands:** `specset tools list` to see what's available, then `specset tools run <name> --input '{...}'` (or `-F key=value`).
|
|
132
|
-
- **As a native MCP server:** `specset mcp` runs a stdio MCP server that surfaces these tools to an MCP client, reusing your CLI login, org, and host. Register it once:
|
|
133
|
-
|
|
134
|
-
```bash
|
|
135
|
-
claude mcp add specset -- specset mcp # Claude Code
|
|
136
|
-
codex mcp add specset -- specset mcp # Codex
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
See the `specset-tools` skill for the full workflow — project scoping, the `-F` JSON-parsing difference, and the `sb://` citation convention.
|
|
78
|
+
Beyond raw GraphQL, the CLI exposes Specset's own retrieval tools — semantic and keyword search with actual content to reason over, not just record previews — as direct commands (`specset tools`) and as a native MCP server (`specset mcp`). The `specset-tools` skill owns that workflow: tool listing, project scoping, the `-F` JSON-parsing difference, MCP registration, and the `sb://` citation convention.
|
|
140
79
|
|
|
141
80
|
## Uploading Files
|
|
142
81
|
|
|
@@ -187,19 +126,11 @@ specset api --query 'query($id: ID!) {
|
|
|
187
126
|
|
|
188
127
|
Processing large PDF sets takes minutes; poll every 15–30 seconds and tell the user what's in flight rather than blocking silently.
|
|
189
128
|
|
|
190
|
-
## Safety
|
|
129
|
+
## Safety
|
|
191
130
|
|
|
192
|
-
|
|
193
|
-
- Confirm with the user before executing mutations that create, update, or delete data.
|
|
194
|
-
- Never hardcode credentials in commands — the CLI manages tokens via OAuth.
|
|
195
|
-
- Tokens live in `~/.config/specset/config.yml`; do not echo or copy that file's contents.
|
|
131
|
+
Confirm with the user before executing mutations that create, update, or delete data. The domain skills note the mutations with non-obvious consequences.
|
|
196
132
|
|
|
197
133
|
## Troubleshooting
|
|
198
134
|
|
|
199
|
-
- `command not found
|
|
200
|
-
- `Not logged in` — run `specset login` (opens the user's browser; tell them to complete sign-in there).
|
|
201
|
-
- `No active organization selected` — run `specset org list`, then `specset org use <slug>`.
|
|
135
|
+
- Auth, org, or missing-CLI errors (`command not found`, `Not logged in`, `No active organization selected`, login hangs) — run the matching First-Run Setup step above.
|
|
202
136
|
- A lookup by id returns `null` without an error — the record usually belongs to a different org than the active one; check `specset auth status` and switch with `specset org use <slug>`.
|
|
203
|
-
- Login hangs or the browser can't reach this machine (SSH, container, CI) — use `specset login --device`: it prints a code + link the user approves from any device.
|
|
204
|
-
- `specset --version` is older than `npm view @specset/cli version`, or a documented flag is missing — run `npm install -g @specset/cli@latest`, then verify with `specset --version`.
|
|
205
|
-
- After upgrading the CLI (`npm i -g @specset/cli@latest`), refresh the skills with `specset skill install --target <claude|codex|chatgpt>`.
|
|
@@ -6,9 +6,7 @@ allowed-tools: Bash Read AskUserQuestion
|
|
|
6
6
|
|
|
7
7
|
# Org Administration
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
Every operation here takes your org id — get it with `{ me { orgMembers { org { id slug name } } } }` if you don't have it. Remember Variable Limitations in the `specset` skill: inline enums, lists, and input objects as literals in the operation text; reserve `-F` for ids and plain strings. When an operation or argument doesn't match this document, introspect (see the `specset` skill → Schema Discovery) rather than guess. These mutations change real people's access and the whole org's appearance — confirm each one with the user before running it.
|
|
9
|
+
Every operation here takes your org id — get it with `{ me { orgMembers { org { id slug name } } } }` if you don't have it. Inline enums, lists, and input objects in the operation text (`-F` is strings-only; Variable Limitations and Schema Discovery live in the `specset` skill). These mutations change real people's access and the whole org's appearance.
|
|
12
10
|
|
|
13
11
|
## Members
|
|
14
12
|
|
|
@@ -35,7 +33,7 @@ Manage them (all take the **membership** id from the queries above, not the user
|
|
|
35
33
|
|
|
36
34
|
- `updateOrgMember(id: ID!, role: ..., projectIds: [ID!])` — `role` is required even when unchanged, so resend the current role when only touching `projectIds`. `projectIds` scopes a Member to specific projects; omit it to leave project access alone.
|
|
37
35
|
- `approveOrgMember(id: ID!)` — activate a `PendingApproval` member.
|
|
38
|
-
- `deactivateOrgMember(id: ID!)` / `reactivateOrgMember(id: ID!)` — suspend and restore access. Deactivation is reversible and preserves history —
|
|
36
|
+
- `deactivateOrgMember(id: ID!)` / `reactivateOrgMember(id: ID!)` — suspend and restore access. Deactivation is reversible and preserves history — prefer it over any form of member deletion.
|
|
39
37
|
|
|
40
38
|
```bash
|
|
41
39
|
specset api --query 'mutation($id: ID!) {
|
|
@@ -88,7 +86,7 @@ specset api --query 'mutation($id: ID!) {
|
|
|
88
86
|
}' -F id=<org-id>
|
|
89
87
|
```
|
|
90
88
|
|
|
91
|
-
|
|
89
|
+
`brand` becomes the button and link color on white backgrounds, so it needs to hold white text. Branding applies to every member of the org — confirm the palette with the user before writing it.
|
|
92
90
|
|
|
93
91
|
### Logos
|
|
94
92
|
|
|
@@ -109,8 +107,6 @@ Use `logoId: $fileId` for the square mark. Passing `null` (inline) clears a slot
|
|
|
109
107
|
|
|
110
108
|
## Safety
|
|
111
109
|
|
|
112
|
-
-
|
|
113
|
-
-
|
|
114
|
-
- Never pass `maxCredits` or `skus` to `updateOrg` — those fields are managed by Specset and the mutation will be rejected.
|
|
115
|
-
- On `updateOrg`, send only the fields you mean to change (plus the full `appearance` object when changing any part of it).
|
|
110
|
+
- For role changes, deactivations, and invite deletions, echo the affected person's email back to the user first — these change real access immediately.
|
|
111
|
+
- `updateOrg` rejects `maxCredits` and `skus` — those fields are managed by Specset. Send only the fields you mean to change (plus the full `appearance` object when changing any part of it).
|
|
116
112
|
- Creating or deleting organizations, SSO, and email-domain management are out of scope for this skill — direct the user to support@specset.com.
|
|
@@ -6,8 +6,6 @@ allowed-tools: Bash Read AskUserQuestion
|
|
|
6
6
|
|
|
7
7
|
# Specset Agent Chat
|
|
8
8
|
|
|
9
|
-
Requires the `specset` CLI, logged in with an active org. If a command fails with `command not found`, `Not logged in`, or `No active organization`, follow First-Run Setup in the `specset` skill.
|
|
10
|
-
|
|
11
9
|
Specset runs its own project-aware AI agent with full access to a project's specs, drawings, submittals, RFIs, and closeout data. `specset agent chat` sends it a message and waits for the full response — use it for questions that need Specset's own project understanding rather than raw data access.
|
|
12
10
|
|
|
13
11
|
## When to Delegate vs. Query Directly
|
|
@@ -6,9 +6,7 @@ allowed-tools: Bash Read AskUserQuestion
|
|
|
6
6
|
|
|
7
7
|
# Closeout & Facilities Data
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
Run every operation with `specset api`. All ids are plain UUIDs. Remember Variable Limitations in the `specset` skill: `-F` sends strings only — inline every enum, number, boolean, list, and input object as a literal in the operation text, and reserve `-F` for ids and plain strings. This document is not exhaustive — when an operation or argument doesn't match, introspect (see the `specset` skill → Schema Discovery) rather than guess.
|
|
9
|
+
Run every operation with `specset api`. All ids are plain UUIDs. Inline enums, numbers, lists, and input objects in the operation text (`-F` is strings-only; Variable Limitations and Schema Discovery live in the `specset` skill).
|
|
12
10
|
|
|
13
11
|
## Entity Model
|
|
14
12
|
|
|
@@ -34,24 +32,6 @@ Real deviations:
|
|
|
34
32
|
|
|
35
33
|
Introspect the input object before composing any create or update, e.g. `{ __type(name: "CreateAssetInput") { inputFields { name type { name kind ofType { name } } } } }`.
|
|
36
34
|
|
|
37
|
-
Worked example — find, then create:
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
specset api --query 'query($projectId: ID!) {
|
|
41
|
-
paginatedAssets(projectId: $projectId, search: "AHU", limit: 20, offset: 0) {
|
|
42
|
-
totalFilteredCount
|
|
43
|
-
items { id tag status location { id name } product { id name } }
|
|
44
|
-
}
|
|
45
|
-
}' -F projectId=<project-id>
|
|
46
|
-
|
|
47
|
-
specset api --query 'mutation($projectId: ID!, $locationId: ID!, $productId: ID!) {
|
|
48
|
-
createAsset(input: {
|
|
49
|
-
projectId: $projectId, locationId: $locationId, productId: $productId,
|
|
50
|
-
tag: "AHU-1", status: Installed, quantity: 1
|
|
51
|
-
}) { id tag status }
|
|
52
|
-
}' -F projectId=<project-id> -F locationId=<location-id> -F productId=<product-id>
|
|
53
|
-
```
|
|
54
|
-
|
|
55
35
|
Prefer `update<Entity>` for changes: pass `id` plus only what changes; pass `null` to clear an optional relationship (e.g. `productId: null`). Update inputs for Asset, Location, Product, Company, and System accept `archived: true` — a reversible soft-archive that drops the record from default lists. Prefer it over delete.
|
|
56
36
|
|
|
57
37
|
## Asset Links
|
|
@@ -109,6 +89,6 @@ The same shape works for duplicate companies, locations, and systems.
|
|
|
109
89
|
|
|
110
90
|
## Safety
|
|
111
91
|
|
|
112
|
-
-
|
|
92
|
+
- Deletes here are hard deletes with no undo — name the exact record (tag/name + id) when confirming.
|
|
113
93
|
- Prefer `update` over delete-and-recreate, and `archived: true` over delete: deleting a product, location, or company silently nulls the references on assets that pointed at it. Check impact first with the filtered list queries.
|
|
114
94
|
- Removing a document linkage can delete the underlying document if nothing else references it — say so when confirming.
|
|
@@ -6,9 +6,7 @@ allowed-tools: Bash Read AskUserQuestion
|
|
|
6
6
|
|
|
7
7
|
# Specset Projects
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
This skill mutates data — confirm with the user before each mutation, and always confirm the project name and which files belong to it before creating anything. Remember Variable Limitations from the `specset` skill: `-F` sends **strings only** — inline every enum, boolean, int, list, and input object as a literal; reserve `-F` for IDs and plain strings. When an operation or argument here doesn't match, introspect (see Schema Discovery in the `specset` skill).
|
|
9
|
+
This skill mutates data — confirm the project name and which files belong to it before creating anything. Inline enums, ints, lists, and input objects in the operation text (`-F` is strings-only; Variable Limitations and Schema Discovery live in the `specset` skill).
|
|
12
10
|
|
|
13
11
|
## Reading Projects
|
|
14
12
|
|
|
@@ -22,7 +20,7 @@ project(id: ID!): Project!
|
|
|
22
20
|
|
|
23
21
|
## Creating a Project
|
|
24
22
|
|
|
25
|
-
`createProject` does **not** add the creator as a project member, so the new project won't appear in the default `projects` list
|
|
23
|
+
`createProject` does **not** add the creator as a project member, so the new project won't appear in the default `projects` list — fetch it by `project(id)`, and add membership as a separate step, mirroring the UI.
|
|
26
24
|
|
|
27
25
|
1. Create it:
|
|
28
26
|
|
|
@@ -103,11 +101,10 @@ updateDrawingSetPrecedence(projectId: ID!, drawingSetIds: [ID!]!): [DrawingSet!]
|
|
|
103
101
|
## Archiving and Deleting
|
|
104
102
|
|
|
105
103
|
- **Prefer `archiveProject(id: ID!)`** — reversible via `unarchiveProject(id: ID!)`. Archived projects drop out of default lists but keep all data.
|
|
106
|
-
- **`deleteProject(id: ID!)` permanently destroys the entire project** — documents, specs, drawings, submittals, RFIs, everything.
|
|
104
|
+
- **`deleteProject(id: ID!)` permanently destroys the entire project** — documents, specs, drawings, submittals, RFIs, everything. Confirm with the user, naming the exact project, before running it. If they just want it out of the way, archive instead.
|
|
107
105
|
|
|
108
106
|
## Troubleshooting
|
|
109
107
|
|
|
110
108
|
- Authorization error on a mutation — the user lacks that permission; the same rules as the UI apply. Surface the message, don't retry.
|
|
111
|
-
- A freshly created project "missing" from `projects` — that's the membership gotcha above, not a failure.
|
|
109
|
+
- A freshly created project "missing" from `projects` — that's the membership gotcha above, not a failure.
|
|
112
110
|
- A document reports a failed processing status on the BulkAction — report it to the user; re-uploading is their call.
|
|
113
|
-
- A lookup by id returns `null` — the record belongs to a different org than the active one; check `specset auth status`.
|
|
@@ -6,15 +6,13 @@ allowed-tools: Bash Read AskUserQuestion
|
|
|
6
6
|
|
|
7
7
|
# Specset RFIs
|
|
8
8
|
|
|
9
|
-
Requires the `specset` CLI, logged in with an active org. If a command fails with `command not found`, `Not logged in`, or `No active organization`, follow First-Run Setup in the `specset` skill.
|
|
10
|
-
|
|
11
9
|
How the data is shaped:
|
|
12
10
|
|
|
13
11
|
- An RFI is a `subject` + `question`, numbered within the project, with a lifecycle `status` (RfiStatus: `Draft | Open | Closed`).
|
|
14
12
|
- `rfiNumber` is unique within a project — `createRfi` rejects a duplicate outright.
|
|
15
13
|
- Responses accumulate on the RFI; exactly one can be marked **official** — the answer of record that justifies closing the RFI.
|
|
16
14
|
|
|
17
|
-
The sketches below are minimal
|
|
15
|
+
The sketches below are minimal — inline enums, ints, and lists in the operation text (`-F` is strings-only; Variable Limitations and Schema Discovery live in the `specset` skill).
|
|
18
16
|
|
|
19
17
|
## Reading
|
|
20
18
|
|
|
@@ -57,21 +55,7 @@ specset api --query 'query($projectId: ID!, $search: String) {
|
|
|
57
55
|
|
|
58
56
|
If the source document carries no number, omit `rfiNumber` and the project's numbering scheme assigns the next one (fetch `nextAvailableRfiNumber` first if the user wants to see it). Numbers you do supply are canonicalized — generic `RFI-` prefixes are normalized — so the stored value may differ slightly from your input; read `rfiNumber` back from the mutation result.
|
|
59
57
|
|
|
60
|
-
|
|
61
|
-
specset api <<'GQL'
|
|
62
|
-
mutation {
|
|
63
|
-
createRfi(input: {
|
|
64
|
-
projectId: "<project-id>"
|
|
65
|
-
subject: "Clarify hollow metal frame anchor spacing"
|
|
66
|
-
question: "Detail 5/A-501 shows anchors at 16 inches; spec 08 11 13 says 24. Which governs?"
|
|
67
|
-
status: Draft
|
|
68
|
-
specSectionIds: ["<spec-section-id>"]
|
|
69
|
-
drawingSheetIds: ["<drawing-sheet-id>"]
|
|
70
|
-
dueDate: "2026-08-01T00:00:00Z"
|
|
71
|
-
}) { id rfiNumber subject status }
|
|
72
|
-
}
|
|
73
|
-
GQL
|
|
74
|
-
```
|
|
58
|
+
`createRfi(input: { projectId, subject, question, status, specSectionIds: [...], drawingSheetIds: [...], dueDate }) { id rfiNumber subject status }`
|
|
75
59
|
|
|
76
60
|
Field conventions:
|
|
77
61
|
|
|
@@ -91,20 +75,9 @@ specset api --query 'mutation($id: ID!) {
|
|
|
91
75
|
|
|
92
76
|
Responses form the answer trail. Attach the reply document via `attachmentCloudFileIds` (file ids come from Uploading Files in the `specset` skill):
|
|
93
77
|
|
|
94
|
-
|
|
95
|
-
specset api <<'GQL'
|
|
96
|
-
mutation {
|
|
97
|
-
createRfiResponse(input: {
|
|
98
|
-
rfiId: "<rfi-id>"
|
|
99
|
-
body: "Use 16-inch anchor spacing per detail 5/A-501; the spec table is superseded."
|
|
100
|
-
attachmentCloudFileIds: ["<file-id>"]
|
|
101
|
-
}) { id isOfficialResponse }
|
|
102
|
-
}
|
|
103
|
-
GQL
|
|
104
|
-
```
|
|
105
|
-
|
|
78
|
+
- `createRfiResponse(input: { rfiId, body, attachmentCloudFileIds: [...] }) { id isOfficialResponse }`
|
|
106
79
|
- `updateRfiResponse(input: { id, body })` — edit a response body.
|
|
107
|
-
- `markRfiResponseAsOfficial(id)` / `unmarkRfiResponseAsOfficial(id)` — designate or revoke the answer of record. There is no official flag on create: create the response first, then mark it.
|
|
80
|
+
- `markRfiResponseAsOfficial(id)` / `unmarkRfiResponseAsOfficial(id)` — designate or revoke the answer of record. There is no official flag on create: create the response first, then mark it. The official response is normally the signed reply of record (typically the architect's or engineer's), not a discussion comment.
|
|
108
81
|
- `deleteRfiResponse(id)` — confirm with the user first.
|
|
109
82
|
|
|
110
83
|
The typical close-out sequence is: `createRfiResponse` → `markRfiResponseAsOfficial` → `updateRfi(input: { id, status: Closed })`.
|
|
@@ -119,6 +92,5 @@ Attachments on the RFI itself carry the question-side documents (sketches, photo
|
|
|
119
92
|
|
|
120
93
|
## Safety
|
|
121
94
|
|
|
122
|
-
- Confirm with the user before every mutation (see Safety Rules in the `specset` skill) — creates included.
|
|
123
95
|
- `deleteRfi(id)` removes the RFI along with its responses and attachments. Prefer closing an RFI over deleting it; delete only on explicit instruction, after showing what will be lost.
|
|
124
96
|
- Marking or unmarking an official response changes the project's answer of record — name the response you're promoting before running it.
|
|
@@ -6,11 +6,9 @@ allowed-tools: Bash Read AskUserQuestion
|
|
|
6
6
|
|
|
7
7
|
# Specset Search
|
|
8
8
|
|
|
9
|
-
Requires the `specset` CLI, logged in with an active org. If a command fails with `command not found`, `Not logged in`, or `No active organization`, follow First-Run Setup in the `specset` skill.
|
|
10
|
-
|
|
11
9
|
This skill is read-only — everything here is a query, so nothing needs user confirmation before running.
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
`-F` sends strings only: inline enums, booleans, ints, and lists as literals in the operation text (Variable Limitations and Schema Discovery live in the `specset` skill).
|
|
14
12
|
|
|
15
13
|
## Choosing an Operation
|
|
16
14
|
|
|
@@ -42,13 +40,13 @@ At least one of `query` or `keywords` is required; they can be combined. Results
|
|
|
42
40
|
{ groups { referenceType totalCount items { url title previewText score projectId projectName } } nextOffset }
|
|
43
41
|
```
|
|
44
42
|
|
|
45
|
-
### Project Scope (`ProjectScope
|
|
43
|
+
### Project Scope (`ProjectScope`)
|
|
46
44
|
|
|
47
45
|
- `CurrentProject` — default; `projectId` is required.
|
|
48
46
|
- `MyProjects` — every project the user is a member of in the org.
|
|
49
47
|
- `AllProjects` — every project in the org. Requires the org **Manager** or **Admin** role — plain Members get an authorization error, so fall back to `MyProjects` when that happens.
|
|
50
48
|
|
|
51
|
-
### Record Types (`SourceReferenceType
|
|
49
|
+
### Record Types (`SourceReferenceType`)
|
|
52
50
|
|
|
53
51
|
Filter with `referenceTypes`. Common values: `SpecSection`, `DrawingSheet`, `Document`, `Submittal`, `SubmittalAttachment`, `Rfi`, and the closeout types `Company`, `Location`, `Product`, `Asset`, `Warranty`, `MaintenanceTask`. Introspect the `SourceReferenceType` enum for the full list.
|
|
54
52
|
|
|
@@ -78,7 +76,7 @@ specSectionByNumber(projectId: ID!, sectionNumber: String!): SpecSection #
|
|
|
78
76
|
drawingSheetByNumber(projectId: ID!, sheetNumber: String!): DrawingSheet # nullable
|
|
79
77
|
```
|
|
80
78
|
|
|
81
|
-
To browse or filter within a project, the paginated lists take `projectId`, an optional `search` string, and `limit`/`offset` ints
|
|
79
|
+
To browse or filter within a project, the paginated lists take `projectId`, an optional `search` string, and `limit`/`offset` ints; both return `{ items totalFilteredCount }`:
|
|
82
80
|
|
|
83
81
|
```graphql
|
|
84
82
|
paginatedSpecSections(projectId: ID!, search: String, limit: Int, offset: Int): SpecSectionPage!
|
|
@@ -87,23 +85,7 @@ paginatedDrawingSheets(projectId: ID!, search: String, limit: Int, offset: Int):
|
|
|
87
85
|
|
|
88
86
|
Useful item fields: `id sectionNumber title numberAndTitle` on SpecSection, `id sheetNumber title` on DrawingSheet.
|
|
89
87
|
|
|
90
|
-
##
|
|
91
|
-
|
|
92
|
-
Semantic search scoped to one project:
|
|
93
|
-
|
|
94
|
-
```bash
|
|
95
|
-
specset api --query 'query($orgId: ID!, $projectId: ID!, $q: String!) {
|
|
96
|
-
search(orgId: $orgId, projectId: $projectId, query: $q,
|
|
97
|
-
projectScope: CurrentProject, limit: 10) {
|
|
98
|
-
groups { referenceType totalCount
|
|
99
|
-
items { url title previewText score } }
|
|
100
|
-
nextOffset
|
|
101
|
-
}
|
|
102
|
-
}' -F orgId=<org-id> -F projectId=<project-id> \
|
|
103
|
-
-F q='vibration isolation requirements for rooftop mechanical equipment'
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
Keyword search filtered to submittals, across all of the user's projects (note the inlined list, enums, and int):
|
|
88
|
+
## Example
|
|
107
89
|
|
|
108
90
|
```bash
|
|
109
91
|
specset api --query 'query($orgId: ID!) {
|
|
@@ -116,18 +98,7 @@ specset api --query 'query($orgId: ID!) {
|
|
|
116
98
|
}' -F orgId=<org-id>
|
|
117
99
|
```
|
|
118
100
|
|
|
119
|
-
Direct lookup by section number:
|
|
120
|
-
|
|
121
|
-
```bash
|
|
122
|
-
specset api --query 'query($projectId: ID!, $n: String!) {
|
|
123
|
-
specSectionByNumber(projectId: $projectId, sectionNumber: $n) {
|
|
124
|
-
id sectionNumber title numberAndTitle
|
|
125
|
-
}
|
|
126
|
-
}' -F projectId=<project-id> -F n='23 05 48'
|
|
127
|
-
```
|
|
128
|
-
|
|
129
101
|
## Working With Results
|
|
130
102
|
|
|
131
|
-
- Each result's `url` is a Specset reference URL
|
|
132
|
-
- Lookups by id are scoped to the **active org**: an id from a different org returns `null` rather than an error. If a known-good id comes back null, check `specset auth status` and switch orgs.
|
|
103
|
+
- Each result's `url` is a Specset reference URL (`sb://spec/<id>`, `sb://sub/<id>`, …); the UUID inside is the record's GraphQL `id` — extract it for follow-up queries. The scheme is documented in the `specset-tools` skill.
|
|
133
104
|
- For follow-up work on what you found — updating submittals, answering RFIs, closeout records, or project/document changes — hand off to the `specset-submittals`, `specset-rfis`, `specset-closeout`, or `specset-projects` skill.
|
|
@@ -6,15 +6,13 @@ allowed-tools: Bash Read AskUserQuestion
|
|
|
6
6
|
|
|
7
7
|
# Specset Submittals
|
|
8
8
|
|
|
9
|
-
Requires the `specset` CLI, logged in with an active org. If a command fails with `command not found`, `Not logged in`, or `No active organization`, follow First-Run Setup in the `specset` skill.
|
|
10
|
-
|
|
11
9
|
How the data is shaped:
|
|
12
10
|
|
|
13
11
|
- `status` (SubmittalStatus: `Draft | Open | Closed`) is the log lifecycle; `workingStatus` (SubmittalWorkingStatus: `Draft | Submitted | Pending | Approved | ApprovedAsNoted | Rejected | ReviseAndResubmit | ForRecordOnly | Void`) is the ball-in-court state. Set either — the server reconciles the other.
|
|
14
12
|
- Revisions are separate submittal records sharing a `submittalNumber`; list and search queries return only the current revision.
|
|
15
13
|
- A submittal number is only unique per (spec section, number) within a project — the bare number alone is not.
|
|
16
14
|
|
|
17
|
-
The sketches below are minimal
|
|
15
|
+
The sketches below are minimal — inline enums, ints, and lists in the operation text (`-F` is strings-only; Variable Limitations and Schema Discovery live in the `specset` skill).
|
|
18
16
|
|
|
19
17
|
## Reading
|
|
20
18
|
|
|
@@ -46,22 +44,9 @@ Also available:
|
|
|
46
44
|
|
|
47
45
|
## Creating
|
|
48
46
|
|
|
49
|
-
Dedupe first: run `searchSubmittals` with the submittal number (or title plus section). A match on (spec section, number) is authoritative — never create a duplicate; the API does not enforce this for you.
|
|
47
|
+
Dedupe first: run `searchSubmittals` with the submittal number (or title plus section). A match on (spec section, number) is authoritative — never create a duplicate; the API does not enforce this for you.
|
|
50
48
|
|
|
51
|
-
|
|
52
|
-
specset api <<'GQL'
|
|
53
|
-
mutation {
|
|
54
|
-
createSubmittal(input: {
|
|
55
|
-
projectId: "<project-id>"
|
|
56
|
-
title: "Hollow Metal Doors and Frames - Product Data"
|
|
57
|
-
submittalNumber: "08 11 13-001"
|
|
58
|
-
specSectionIds: ["<spec-section-id>"]
|
|
59
|
-
submittalTypeId: "<submittal-type-id>"
|
|
60
|
-
status: Draft
|
|
61
|
-
}) { id submittalNumber title }
|
|
62
|
-
}
|
|
63
|
-
GQL
|
|
64
|
-
```
|
|
49
|
+
`createSubmittal(input: { projectId, title, submittalNumber, specSectionIds: [...], submittalTypeId, status }) { id submittalNumber title }` — omit `submittalNumber` to auto-number in the project's sequence.
|
|
65
50
|
|
|
66
51
|
**From a PDF**: upload it first (see Uploading Files in the `specset` skill) and pass the resulting file id as `cloudFileId` — Specset extracts the number, title, and section from the document, so you can omit them. Add `autoReviewMode: GeneratePlanAndApprove` to start an AI compliance review in the same call (`GeneratePlan` pauses at the plan for approval; default `None`).
|
|
67
52
|
|
|
@@ -96,52 +81,19 @@ File ids come from Uploading Files in the `specset` skill.
|
|
|
96
81
|
|
|
97
82
|
Track who reviews the submittal and what they returned:
|
|
98
83
|
|
|
99
|
-
|
|
100
|
-
specset api <<'GQL'
|
|
101
|
-
mutation {
|
|
102
|
-
createSubmittalApprover(input: {
|
|
103
|
-
submittalId: "<submittal-id>"
|
|
104
|
-
userId: "<user-id>"
|
|
105
|
-
dueDate: "2026-08-01T00:00:00Z"
|
|
106
|
-
responseRequired: true
|
|
107
|
-
}) { id order status }
|
|
108
|
-
}
|
|
109
|
-
GQL
|
|
110
|
-
```
|
|
84
|
+
- `createSubmittalApprover(input: { submittalId, userId, dueDate, responseRequired }) { id order status }`
|
|
111
85
|
|
|
112
86
|
Record a returned response with `updateSubmittalApprover(input: { id, status: ApprovedAsNoted, comment: "...", returnedDate: "...", cloudFileIds: [...] })`. `status` is SubmittalApproverResponseStatus: `Approved | ApprovedAsNoted | ForRecordOnly | Pending | Rejected | ReviseAndResubmit | Void | Submitted`. `approverType` distinguishes `Approver` (default) from `Submitter`; `sentDate` and `distributed` track routing. Remove with `deleteSubmittalApprover(id)`.
|
|
113
87
|
|
|
114
88
|
## AI Compliance Reviews
|
|
115
89
|
|
|
116
|
-
Three steps
|
|
117
|
-
|
|
118
|
-
```bash
|
|
119
|
-
# 1. Start the review
|
|
120
|
-
specset api --query 'mutation($submittalId: ID!) {
|
|
121
|
-
createSubmittalReview(submittalId: $submittalId, createMode: GeneratePlanAndApprove) { id }
|
|
122
|
-
}' -F submittalId=<submittal-id>
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
Optional: `prompt` (focus instructions, a plain string), and `specSectionIds` / `drawingSheetIds` (inline lists) to pin the spec basis.
|
|
90
|
+
Three steps — arguments are top-level (no input object):
|
|
126
91
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
specset api --query 'query($id: ID!) {
|
|
131
|
-
submittalReview(id: $id) { id status oneLiner lastReviewedAt }
|
|
132
|
-
}' -F id=<review-id>
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
`status` is the verdict, ReviewStatus: `Compliant | NonCompliant | MissingInfo | ClarificationsNeeded | NotApplicable`.
|
|
136
|
-
|
|
137
|
-
```bash
|
|
138
|
-
# 3. Compile the annotated, marked-up PDF
|
|
139
|
-
specset api --query 'mutation($id: ID!) {
|
|
140
|
-
compileSubmittalReview(id: $id, includeIssueToc: true) { id compiledReview { id } }
|
|
141
|
-
}' -F id=<review-id>
|
|
142
|
-
```
|
|
92
|
+
1. `createSubmittalReview(submittalId, createMode: GeneratePlanAndApprove) { id }` — optional: `prompt` (focus instructions, a plain string), and `specSectionIds` / `drawingSheetIds` (inline lists) to pin the spec basis.
|
|
93
|
+
2. Poll `submittalReview(id) { id status oneLiner lastReviewedAt }` until `lastReviewedAt` is set — reviews take minutes; see Waiting on Background Processing in the `specset` skill for cadence. `status` is the verdict, ReviewStatus: `Compliant | NonCompliant | MissingInfo | ClarificationsNeeded | NotApplicable`.
|
|
94
|
+
3. `compileSubmittalReview(id, includeIssueToc: true) { id compiledReview { id } }` compiles the annotated, marked-up PDF. `excludedIssueIds: [...]` (inlined) drops chosen issues from the compiled PDF and TOC.
|
|
143
95
|
|
|
144
|
-
`
|
|
96
|
+
`updateSubmittalReview(id, comments)` records reviewer comments; `deleteSubmittalReview(id)` removes a review.
|
|
145
97
|
|
|
146
98
|
## Drafting a Whole Submittal Log
|
|
147
99
|
|
|
@@ -159,6 +111,4 @@ Applying skips rows whose (section, number) already exists and writes per-row re
|
|
|
159
111
|
|
|
160
112
|
## Safety
|
|
161
113
|
|
|
162
|
-
|
|
163
|
-
- `deleteSubmittal(id)` removes one revision. `deleteSubmittal(id, deleteAllRevisions: true)` removes the entire revision chain — state that difference and get explicit confirmation before using it.
|
|
164
|
-
- Never loop deletes over a list the user hasn't seen.
|
|
114
|
+
`deleteSubmittal(id)` removes one revision; `deleteSubmittal(id, deleteAllRevisions: true)` removes the entire revision chain — state that difference when confirming the delete.
|
|
@@ -6,8 +6,6 @@ allowed-tools: Bash Read AskUserQuestion
|
|
|
6
6
|
|
|
7
7
|
# Specset Agent Tools (`specset tools`, `specset mcp`)
|
|
8
8
|
|
|
9
|
-
Requires the `specset` CLI, logged in with an active org. If a command fails with `command not found`, `Not logged in`, or `No active organization`, follow First-Run Setup in the `specset` skill.
|
|
10
|
-
|
|
11
9
|
These are the same read-only retrieval tools Specset's own in-app agent uses — exposed so external agents can call them directly. Everything here is read-only; nothing needs user confirmation.
|
|
12
10
|
|
|
13
11
|
## When to use which surface
|
|
@@ -50,12 +48,29 @@ Output is the tool's JSON payload (`{ success, message?, result? }`); a `{ succe
|
|
|
50
48
|
|
|
51
49
|
### Identifiers are citation IDs, not links
|
|
52
50
|
|
|
53
|
-
Tool results embed identifiers shaped like `sb://spec/<uuid>` or `sb://drawing/<uuid>`. Pass them back into other tools verbatim (e.g. into `getSpecSectionContent`, `getDrawingSheet`). They are
|
|
51
|
+
Tool results embed identifiers shaped like `sb://spec/<uuid>` or `sb://drawing/<uuid>`. Pass them back into other tools verbatim (e.g. into `getSpecSectionContent`, `getDrawingSheet`). They are citation identifiers, not web URLs.
|
|
54
52
|
|
|
55
53
|
### Project scoping
|
|
56
54
|
|
|
57
55
|
Most tools are project-scoped. Either pass `--project` (a UUID or `sb://project/...`), or include `projectId` in the tool input. Use `listProjects` to discover project IDs. With `--project` set, per-call `projectId` becomes optional.
|
|
58
56
|
|
|
57
|
+
## Downloading source files (drawings, documents, specs, submittals, RFIs)
|
|
58
|
+
|
|
59
|
+
The retrieval tools return **extracted text**, which is authoritative for schedules, notes, and spec paragraphs — but cannot answer spatial/visual questions (routing, clearances, what a plan view actually shows) and never carries the original file. Every entity has a download command, and **each accepts its `sb://` citation URL verbatim** (as returned by issues, search, and tool results — any `#page=`/`#nodeId=` fragment is ignored) or a bare UUID:
|
|
60
|
+
|
|
61
|
+
| Entity | Command | Also accepts | Formats / options |
|
|
62
|
+
|---|---|---|---|
|
|
63
|
+
| Drawing sheets | `specset drawings download 'sb://drawing/<uuid>'` | sheet number + `--project` | `--format image` (rendered PNG, default), `pdf` (single sheet), `file` (whole set) |
|
|
64
|
+
| Documents | `specset docs download 'sb://doc/<uuid>'` | | also covers RFI attachments and closeout documents |
|
|
65
|
+
| Spec sections | `specset specs download 'sb://spec/<uuid>'` | section number (e.g. `'23 31 19'`) + `--project` | per-section PDF slice (default), `--asset book` (whole source spec file) |
|
|
66
|
+
| Submittals | `specset submittals download 'sb://sub/<uuid>'` | | compiled package (default when present); `--list` shows the asset inventory; `--asset attachment --index 2`, `--asset attachment --all` |
|
|
67
|
+
| RFIs | `specset rfis download 'sb://rfi/<uuid>'` | | question + response attachments; `--list`, `--all` |
|
|
68
|
+
| File resources | `specset files download 'sb://file/<uuid>'` | | escape hatch when you already hold an `sb://file` id |
|
|
69
|
+
|
|
70
|
+
All commands support `--json` (structured `{files: [{path, bytes, ...}]}` output) and `--out` (file path, or directory for multi-file downloads). A citation passed to the wrong command errors with the right one to use.
|
|
71
|
+
|
|
72
|
+
Typical loop for drawings: search or `getDrawingSheetContent` to find the sheet → hit a visual question the text can't settle → `drawings download` → read the PNG to inspect the geometry.
|
|
73
|
+
|
|
59
74
|
## MCP server (Claude Code, Codex, other MCP clients)
|
|
60
75
|
|
|
61
76
|
`specset mcp` runs a stdio MCP server that exposes these tools natively, reusing your CLI login, org, and host config. Register it once and the client can call the tools directly:
|