@specset/cli 1.0.0 → 2.0.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/README.md +55 -2
- package/THIRD_PARTY_NOTICES.md +7 -1
- package/dist/main.js +46419 -13516
- package/package.json +7 -3
- package/plugin/specset/.claude-plugin/plugin.json +1 -1
- package/plugin/specset/.codex-plugin/plugin.json +6 -3
- package/plugin/specset/assets/icon.png +0 -0
- package/plugin/specset/skills/specset/SKILL.md +13 -3
- package/plugin/specset/skills/specset-admin/SKILL.md +21 -7
- package/plugin/specset/skills/specset-agent/SKILL.md +131 -2
- package/plugin/specset/skills/specset-closeout/SKILL.md +151 -4
- package/plugin/specset/skills/specset-issues/SKILL.md +27 -0
- package/plugin/specset/skills/specset-projects/SKILL.md +42 -17
- package/plugin/specset/skills/specset-submittals/SKILL.md +11 -2
- package/plugin/specset/skills/specset-tools/SKILL.md +44 -6
- package/skills/specset/SKILL.md +13 -3
- package/skills/specset-admin/SKILL.md +21 -7
- package/skills/specset-agent/SKILL.md +131 -2
- package/skills/specset-closeout/SKILL.md +151 -4
- package/skills/specset-issues/SKILL.md +27 -0
- package/skills/specset-projects/SKILL.md +42 -17
- package/skills/specset-submittals/SKILL.md +11 -2
- package/skills/specset-tools/SKILL.md +44 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@specset/cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Command-line interface for Specset — authenticate, run GraphQL queries, and chat with Specset project agents.",
|
|
5
5
|
"license": "Elastic-2.0",
|
|
6
6
|
"homepage": "https://specset.com",
|
|
@@ -17,14 +17,18 @@
|
|
|
17
17
|
"agent"
|
|
18
18
|
],
|
|
19
19
|
"engines": {
|
|
20
|
-
"node": ">=
|
|
20
|
+
"node": ">=22"
|
|
21
21
|
},
|
|
22
22
|
"type": "module",
|
|
23
23
|
"bin": {
|
|
24
24
|
"specset": "./dist/main.js"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"
|
|
27
|
+
"@anthropic-ai/claude-agent-sdk": "0.3.296",
|
|
28
|
+
"@anthropic-ai/sdk": "0.93.0",
|
|
29
|
+
"@modelcontextprotocol/sdk": "^1.31.0",
|
|
30
|
+
"open": "^11.0.0",
|
|
31
|
+
"zod": "^4.1.9"
|
|
28
32
|
},
|
|
29
33
|
"publishConfig": {
|
|
30
34
|
"access": "public"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specset",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Search and manage Specset construction project data with shared skills and MCP tools.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Specset",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"mcpServers": "./.mcp.json",
|
|
21
21
|
"interface": {
|
|
22
22
|
"displayName": "Specset",
|
|
23
|
-
"shortDescription": "Search
|
|
23
|
+
"shortDescription": "Search construction documents",
|
|
24
24
|
"longDescription": "Use Specset skills and MCP tools to search specifications and drawings, inspect project records, manage workflows, and transfer files.",
|
|
25
25
|
"developerName": "Specset",
|
|
26
26
|
"category": "Productivity",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"File transfer"
|
|
31
31
|
],
|
|
32
32
|
"websiteURL": "https://specset.com",
|
|
33
|
+
"supportURL": "https://specset.com/contact",
|
|
33
34
|
"privacyPolicyURL": "https://specset.com/privacy",
|
|
34
35
|
"termsOfServiceURL": "https://specset.com/terms",
|
|
35
36
|
"defaultPrompt": [
|
|
@@ -37,6 +38,8 @@
|
|
|
37
38
|
"Compare this submittal with the specifications.",
|
|
38
39
|
"Show me the latest RFIs affecting this work."
|
|
39
40
|
],
|
|
40
|
-
"brandColor": "#1F6FEB"
|
|
41
|
+
"brandColor": "#1F6FEB",
|
|
42
|
+
"composerIcon": "./assets/icon.png",
|
|
43
|
+
"logo": "./assets/icon.png"
|
|
41
44
|
}
|
|
42
45
|
}
|
|
Binary file
|
|
@@ -21,6 +21,7 @@ This is the core skill — setup and mechanics only. Domain workflows live in si
|
|
|
21
21
|
| `specset-projects` | Creating projects, uploading spec/drawing PDFs, publishing spec and drawing sets |
|
|
22
22
|
| `specset-submittals` | Submittal lifecycle, attachments, approvers, and AI compliance reviews |
|
|
23
23
|
| `specset-rfis` | RFI logging, tracking, and responses |
|
|
24
|
+
| `specset-issues` | Listing a project's design-review issues and their verification verdicts |
|
|
24
25
|
| `specset-closeout` | Assets, locations, products, companies, warranties, and maintenance |
|
|
25
26
|
| `specset-agent` | Delegating deep project questions to Specset's in-app AI agent |
|
|
26
27
|
| `specset-admin` | Org members, invites, and whitelabel branding |
|
|
@@ -31,8 +32,8 @@ This is the core skill — setup and mechanics only. Domain workflows live in si
|
|
|
31
32
|
|
|
32
33
|
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
34
|
|
|
34
|
-
1. **Install or update the CLI** (Node.js
|
|
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.
|
|
35
|
+
1. **Install or update the CLI** (Node.js 22+). 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>`.
|
|
36
|
+
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. When any command answers `Session invalid`, run `specset login` (or `--device`) for that host again: it replaces the stored session the server no longer accepts. `specset logout` is only for switching accounts.
|
|
36
37
|
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
38
|
4. **Confirm** with `specset auth status`.
|
|
38
39
|
|
|
@@ -59,6 +60,14 @@ query {
|
|
|
59
60
|
GQL
|
|
60
61
|
```
|
|
61
62
|
|
|
63
|
+
### Organization scope
|
|
64
|
+
|
|
65
|
+
Calls run in the active organization (`specset org use <slug>`). Pass `--org <slug|id>` to pin a different org for one call — required when the project belongs to another org, and safer in parallel sessions because the active org is shared config that another session can switch mid-task. `--noOrg` omits the org header entirely for global/superadmin operations; the two flags are mutually exclusive.
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
specset api --org poettker --query '{ paginatedAssets(projectId: "…", limit: 5) { totalFilteredCount } }'
|
|
69
|
+
```
|
|
70
|
+
|
|
62
71
|
### Variable Limitations
|
|
63
72
|
|
|
64
73
|
`-F key=value` only sends **string** values. For non-string args (numbers, booleans, enums, input objects, lists), inline literals directly in the operation rather than parameterizing them. Reserve `-F` for IDs and plain strings.
|
|
@@ -108,7 +117,7 @@ specset api --query 'query($id: ID!) {
|
|
|
108
117
|
}' -F id=<bulk-action-id>
|
|
109
118
|
```
|
|
110
119
|
|
|
111
|
-
Processing large PDF sets takes minutes; poll every 15–30 seconds and tell the user what's in flight rather than blocking silently.
|
|
120
|
+
Processing large PDF sets takes minutes; poll every 15–30 seconds and tell the user what's in flight rather than blocking silently. A workflow `status` of `Queued` (documents from an integration sync, an upload of more than 10 files, a portal or a reprocess) means it is waiting its turn for background processing: count it as in progress, like `NotStarted` and `Running`.
|
|
112
121
|
|
|
113
122
|
## Safety
|
|
114
123
|
|
|
@@ -116,5 +125,6 @@ Confirm with the user before executing mutations that create, update, or delete
|
|
|
116
125
|
|
|
117
126
|
## Troubleshooting
|
|
118
127
|
|
|
128
|
+
- A server/network failure while selecting the organization (for example HTTP 502) — check the pinned host and server availability, then retry the same command. This does not establish a login-policy failure.
|
|
119
129
|
- 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.
|
|
120
130
|
- 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>`.
|
|
@@ -31,7 +31,7 @@ specset api --query 'query($orgId: ID!, $search: String) {
|
|
|
31
31
|
|
|
32
32
|
Manage them (all take the **membership** id from the queries above, not the user id):
|
|
33
33
|
|
|
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;
|
|
34
|
+
- `updateOrgMember(id: ID!, role: ..., projectIds: [ID!], teamIds: [ID!])` — `role` is required even when unchanged, so resend the current role when only touching `projectIds`. `projectIds` scopes a Member to specific projects (the projects they were added to themselves; ones they're on through a team come with the team); `teamIds` replaces their teams. Omit either to leave it alone. Adding or removing a project, or a team's projects, needs management permission in each of those projects.
|
|
35
35
|
- `approveOrgMember(id: ID!)` — activate a `PendingApproval` member.
|
|
36
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.
|
|
37
37
|
|
|
@@ -41,17 +41,31 @@ specset api --query 'mutation($id: ID!) {
|
|
|
41
41
|
}' -F id=<org-member-id>
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
##
|
|
44
|
+
## Teams
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
A team is a named group of members. Assigning a team to a project puts everyone on it on that project, and changes to the team carry over to every project it's on. Teams don't carry a role: people keep their org role unless a project role is set on them.
|
|
47
|
+
|
|
48
|
+
- `teams(orgId: ID!)` — select `{ id name members { orgMember { user { email } } } projects { project { id name } } canManage }`.
|
|
49
|
+
- `createTeam(orgId: ID!, name: String!, userIds: [ID!], projectIds: [ID!])`, `updateTeam(id: ID!, name: String, userIds: [ID!], projectIds: [ID!])` (lists replace; assignments to archived projects stay), `deleteTeam(id: ID!)`.
|
|
50
|
+
- On a project: `projectTeams(projectId: ID!)`, `addProjectMembers(projectId: ID!, userIds: [ID!], teamIds: [ID!])`, `removeProjectTeam(id: ID!)` (takes the `ProjectTeam` id).
|
|
51
|
+
|
|
52
|
+
Changing a team needs org Manager or Admin and management permission in every project the team is on or will be on; `canManage` says whether you have it.
|
|
53
|
+
|
|
54
|
+
## Adding Users and Invites
|
|
55
|
+
|
|
56
|
+
Nobody joins an org on someone else's say-so. Both paths below leave the person with a pending invitation they must accept — in the app (existing Specset users see an invite badge), by registering through the invite link, or by signing in with the org's SSO. Until then an added user is an `Invited` member: visible in pickers and assignable, but with no access.
|
|
57
|
+
|
|
58
|
+
- `createOrgMember(orgId: ID!, email: String!, firstName: String!, lastName: String!, role: ..., projectIds: [ID!], teamIds: [ID!], sendInvite: Boolean)` — adds the person as an `Invited` seat right away so they can be assigned work before they've joined. `sendInvite: true` emails the invite link; existing Specset users get the in-app invitation either way. Returns the `OrgMember` (`status: Invited`).
|
|
59
|
+
- `createOrgInvite(orgId: ID!, email: String!, role: ..., projectIds: [ID!])` — invite-only (no seat until they accept; no `teamIds`, so add teams once they have a seat); also used to (re-)invite an existing `Invited` seat. `projectIds` (optional, inline the list) pre-scopes a Member to specific projects. Set `role` deliberately — don't default people to more access than they need. Share the returned `inviteUrl` if the email might not land.
|
|
60
|
+
- `orgInvites(orgId: ID!)` / `paginatedOrgInvites(orgId: ID!, first: Int, after: String)` — pending invites; select `{ id user { email } role inviteUrl }`.
|
|
48
61
|
- `updateOrgInvite(id: ID!, role: ..., projectIds: [ID!])` — `role` is required.
|
|
49
|
-
- `
|
|
62
|
+
- `resendOrgInvite(id: ID!)` — rotates the link and re-sends the email.
|
|
63
|
+
- `deleteOrgInvite(id: ID!)` — revoke a pending invite (an `Invited` seat stays, as "Not invited"; `deleteOrgMember` removes the seat).
|
|
50
64
|
|
|
51
65
|
```bash
|
|
52
66
|
specset api --query 'mutation($orgId: ID!, $email: String!) {
|
|
53
|
-
|
|
54
|
-
id email
|
|
67
|
+
createOrgMember(orgId: $orgId, email: $email, firstName: "Alex", lastName: "Rivera", role: Member, sendInvite: true) {
|
|
68
|
+
id status user { email }
|
|
55
69
|
}
|
|
56
70
|
}' -F orgId=<org-id> -F email=alex@example.com
|
|
57
71
|
```
|
|
@@ -29,22 +29,151 @@ specset agent chat --project <projectId> -m "What mechanical equipment is schedu
|
|
|
29
29
|
# Continue the same conversation (thread id is in the first response)
|
|
30
30
|
specset agent chat --thread <threadId> -m "Which of those have submittals?"
|
|
31
31
|
|
|
32
|
+
# Attach local files to a new conversation or a follow-up message
|
|
33
|
+
specset agent chat --project <projectId> --file "RFI template.pdf" \
|
|
34
|
+
-m "Use this template to draft the RFI."
|
|
35
|
+
|
|
32
36
|
# Review a past conversation
|
|
33
37
|
specset agent show <threadId>
|
|
38
|
+
|
|
39
|
+
# Download a generated document (artifact ids are included in agent show)
|
|
40
|
+
specset agent export <artifactId> --format docx --out ./filled-rfi.docx
|
|
41
|
+
specset agent export <artifactId> --format pdf --out ./filled-rfi.pdf
|
|
42
|
+
|
|
43
|
+
# Pin the host and organization when inspecting a run on another deployment
|
|
44
|
+
specset agent show <threadId-or-link> --host <host> --org <slug-or-id> --json
|
|
45
|
+
|
|
34
46
|
```
|
|
35
47
|
|
|
36
48
|
Use `--json` for machine-readable output (all commands accept it). Long-running questions may need `--timeout <seconds>` — document analysis can take a few minutes.
|
|
37
49
|
|
|
50
|
+
`--file <path>` uploads and attaches a file through the same processing flow as
|
|
51
|
+
the app. Repeat it for multiple attachments; PDF, Word, Excel and image MIME types
|
|
52
|
+
are inferred from the extension. It also works with `agent start` and with
|
|
53
|
+
`chat --thread` to attach files to an existing conversation. The upload belongs to
|
|
54
|
+
the thread's organization. Use `--detach` to return the thread id immediately
|
|
55
|
+
while the attachment processing and response continue.
|
|
56
|
+
|
|
57
|
+
`agent export` supports document artifacts in Word/PDF. Prepared templates retain
|
|
58
|
+
their original formatting; other documents are rebuilt from their saved markdown.
|
|
59
|
+
For documents edited in Pages, export in the app to preserve Pages layout,
|
|
60
|
+
headers, and notes. Other artifact types have their own export formats in the app.
|
|
61
|
+
A delegated draft has its own thread, so run `agent show` on the returned child
|
|
62
|
+
thread to find its artifact id.
|
|
63
|
+
|
|
38
64
|
Agent transcripts expose their source references as clickable `https://app.specbook.ai/go/...` links. Preserve the most relevant returned links as descriptive Markdown citations when relaying the answer to the user. Do not fabricate additional links from UUIDs. An identifier that is not an `https://` link (a thread-local short id or `doc:`-prefixed identifier) is internal — pass it back into commands verbatim, but never present it to the user as a clickable link. Both `--project` and `--thread` accept returned Specset links as well as UUIDs.
|
|
39
65
|
|
|
40
66
|
Find a project id first if you don't have one:
|
|
41
67
|
|
|
42
68
|
```bash
|
|
43
|
-
specset
|
|
69
|
+
specset projects list --json
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Starting a Review Session Directly
|
|
73
|
+
|
|
74
|
+
Start a Quick Project Review investigation with an explicit brief and bounded
|
|
75
|
+
scope. Project Review remains a superadmin-only option in the agent picker;
|
|
76
|
+
shared organization and project access checks also apply.
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
specset agent start --type ProjectReview --project <projectId> --noAutoApprovePlan \
|
|
80
|
+
--title "Building coordination pilot" \
|
|
81
|
+
-m "Review Building 720.1 at Quick effort for cross-discipline coordination problems. Prioritize the strongest leads and report what you did not examine."
|
|
82
|
+
specset agent show <threadId>
|
|
83
|
+
specset agent approve <threadId> --tool finalizePlan --wait --timeout 1800
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Pin the same `--host` on each command for a development deployment. Inspect the
|
|
87
|
+
short markdown plan before approving. Quick is the default: after approval, the
|
|
88
|
+
root investigates directly with drawing, graph, specification and document tools,
|
|
89
|
+
files issues, and reports examination limits. Standard and Deep use investigation
|
|
90
|
+
workers within the approved budget. All efforts use the agentic review route. Server step
|
|
91
|
+
backstops are not work targets or dollar caps; automatic issue verification follows
|
|
92
|
+
project policy and adds separate cost.
|
|
93
|
+
|
|
94
|
+
Drawing graph navigation is automatic for eligible projects. Use
|
|
95
|
+
`drawings build-graph --project <projectId> --wait` only for an explicit rebuild.
|
|
96
|
+
Inspect `getDrawingGraphOverview` bundles and quality flags before a benchmark;
|
|
97
|
+
building the graph does not reprocess stale source nodes. `--autoApprovePlan`
|
|
98
|
+
allows immediate execution when the brief is already approved.
|
|
99
|
+
`agent approve --deny --reason "…"` rejects a pending proposal for revision.
|
|
100
|
+
`agent stop <threadId>` cancels a running review and its descendants.
|
|
101
|
+
|
|
102
|
+
Long-running agents — Design Review, Drawing Review, Design Quality Review, Structured Review, Submittal Log — can be started as their own session without going through a Conversation thread. `specset agent start` creates the thread with the given `--type`, titles it, seeds it with your kickoff instructions, and returns immediately with the thread id; the run continues on the server.
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
specset agent start --type DesignReview --project <projectId> \
|
|
106
|
+
--title "Building 720.1 - Design Review" --autoApprovePlan \
|
|
107
|
+
-m "Run a design review restricted to the Building 720.1 spec and drawing areas. Omit the master / no-area pass. Building 720.1's own specifications govern; Appendix A is a backup reference only."
|
|
108
|
+
|
|
109
|
+
specset agent show <threadId> # progress, transcript, findings so far
|
|
110
|
+
|
|
111
|
+
# A Drawing Review runs graph-planned coordination checks; select them up front.
|
|
112
|
+
specset agent start --type DrawingReview --project <projectId> \
|
|
113
|
+
--coordinationTaskTypes ElectricalDistribution,ArchitectureMepPenetrations \
|
|
114
|
+
--drawingArea "Building 720.1" --title "Building 720.1 - Coordination" \
|
|
115
|
+
-m "Coordinate the selected systems for Building 720.1."
|
|
44
116
|
```
|
|
45
117
|
|
|
118
|
+
- `--type` accepts any top-level agent type (`DesignReview`, `DrawingReview`, `DesignQualityReview`, `StructuredReview`, `SubmittalLog`, …). The kickoff message is the review's scope: name the building areas, disciplines, sections or sheets, what to exclude, and any special coordination checks — the same text a user would type when launching the review in the app.
|
|
119
|
+
- `--type DrawingReview` also needs `--coordinationTaskTypes` (`all`, or a comma-separated subset of the 16 families: `CeilingOverhead`, `EquipmentPowerControls`, `LifeSafetyEgress`, `ArchitectureStructureOpenings`, `ArchitectureMepPenetrations`, `StructuralMepInterfaces`, `EnvelopeWaterproofing`, `FireLifeSafetyProtection`, `CivilSiteUtilities`, `ElectricalDistribution`, `MechanicalSystemsContinuity`, `PlumbingSystemsContinuity`, `StructuralSystemsContinuity`, `FireSuppressionSystemsContinuity`, `FireAlarmEmergencyCommunications`, `TechnologySecurityCommunications`). The server refuses a Drawing Review whose first message carries no scope, and the scope cannot change afterwards, so these flags apply only to new threads. `--drawingArea` limits the review to one building-scoped drawing area, and `--noDrawingArea` limits it to the sheets that belong to no drawing area (the site-wide set; exclusive with `--drawingArea`); `--coordinationTaskIds` narrows it to exact graph task ids for a bounded pilot or rerun (ids must belong to the selected families and area). `--executionIntent` decides how earlier reviews' runs of the same tasks are treated: `Reuse` (the default) answers a task from another review's completed run while the drawings it read are unchanged and leaves Blocked or Failed tasks alone (reported as incomplete), `RetryIncomplete` also re-runs those, and `Fresh` ignores earlier runs. The project needs a current drawing graph (`drawingCoordinationReviewAvailability.graphState` is `Ready`); otherwise the review cannot start.
|
|
120
|
+
- Local Drawing Review kickoff uses the same required `--coordinationTaskTypes` and optional `--coordinationTaskIds` / `--drawingArea` flags as `agent start`. Pass them with the first message to `agent serve`; an existing thread keeps its original scope.
|
|
121
|
+
- `--autoApprovePlan` skips plan sign-off. To inspect a plan before execution, pass `--noAutoApprovePlan`: this also disables the CLI's default blanket tool approval, so the session parks at `finalizePlan`. Approve it with `agent approve <threadId> --tool finalizePlan`. Omitting the flag preserves the existing plan setting, but blanket approval defaults on. `--isolateIssues` hides the project's pre-existing issues; `--noIsolateIssues` explicitly restores ordinary issue reads. `--reviewEffort Quick|Standard|Deep` sets a Project Review's effort: Quick investigates the strongest few leads on the root; Standard covers the brief within an approved worker budget; Deep covers the whole surveyed inventory. The plan states the expected worker count and estimated worker cost for approval. Omitting it keeps the thread's setting (Quick for a new thread). For a quick test of a Standard or Deep review, `--reviewMaxWorkers 3` caps the workers it starts (the server refuses more; the root records the rest as not examined). Native tools let a local run's harness use its own tools in the run's workspace and run sandboxed code over document and drawing reads, cropping and enlarging a detail. A thread that starts running locally has them on unless it already chose; `--noNativeTools` (both commands) or the conversation's Settings toggle turns them off.
|
|
122
|
+
- `--title` names the session in Agent Sessions. `agent start` is `agent chat --detach` for a new thread; use `chat --type … --timeout …` instead when you want to wait for a short run to finish.
|
|
123
|
+
|
|
46
124
|
## Notes
|
|
47
125
|
|
|
48
126
|
- Keep one thread per topic: follow-ups via `--thread` give the agent the prior context and produce better answers than fresh threads.
|
|
49
|
-
-
|
|
127
|
+
- `agent chat` approves every tool by default, so changes the agent makes (creating submittals, updating records) are applied without a confirmation step. Confirm with the user before asking it to change data, or pass `--noAutoApprove` so its proposals wait for approval in the Specset UI or `agent approve`. To make changes headlessly yourself, use the mutations documented in the domain skills.
|
|
50
128
|
- The agent answers from the project you scope it to; double-check the `--project` id when results look unrelated.
|
|
129
|
+
|
|
130
|
+
## Run agent threads locally with your own Claude Code / Codex
|
|
131
|
+
|
|
132
|
+
`specset agent serve` connects this machine to Specset. A conversation switched to **Execute locally** (conversation Settings) runs its model calls through the user's own coding harness (Claude Code or Codex) instead of a cloud model, while Specset keeps the agent loop, its tools, approvals and the transcript. Nothing else changes for the user: the thread stays the record.
|
|
133
|
+
|
|
134
|
+
Install the Codex runtime once (Node.js 22 or newer); Claude uses the runtime bundled with the CLI:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
specset harness install codex # pins the native Codex runtime under ~/.specset/harness
|
|
138
|
+
specset harness list # what is installed, and which harness launched this shell
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Codex uses `CODEX_PATH` when set, then `codex` on PATH, then the managed runtime. Claude uses the bundled SDK runtime, then `claude` on PATH. Log in to the harness itself first (`claude auth login`, `codex login`); provider failures such as an exhausted usage limit end the affected run with one visible error.
|
|
142
|
+
|
|
143
|
+
**When the user asks to run a thread locally**, start the runner in the background so your own tool timeout does not cut it off, then check the thread:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
specset agent serve --host <deployment> --org <slug> & # --account claude2,codex limits it to those accounts
|
|
147
|
+
specset agent show <thread link> # the transcript so far
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
What the harness spends is recorded on the thread as unbilled local usage (per model, priced for information only) and kept out of Specset's cost and credit figures.
|
|
151
|
+
|
|
152
|
+
### Native tools and the run workspace
|
|
153
|
+
|
|
154
|
+
Native tools are on for a thread that starts running locally, unless the thread already chose (an earlier on or off stands): the harness can then run shell commands and read, search or edit files in the run workspace. Turn them off with **Native tools** in the conversation's Settings or `--noNativeTools`; with them off, the harness only calls Specset functions, which the server authorizes and executes (approvals stay in the web app). Each action is mirrored into the conversation as a local action card, and the thread's **Permissions** setting bounds what happens without asking: Read only, Accept edits, Auto (edits accepted, escalations reviewed) or Full access; for Codex these map to its sandbox (read-only, workspace-write, full access). Native sub-agents stay off; Specset's own sub-agent and fan-out tools run through the same machine.
|
|
155
|
+
|
|
156
|
+
Each run (a root thread and its children) works in one private directory under `--directory` (`~/.specset/personal-runs/<runner>/runs/<thread>/` by default) with `specs/`, `drawings/`, `docs/`, `inputs/` and `out/`. It starts empty. The `specset` CLI is logged in inside the session as the user for that host and organization, so the harness downloads what it needs: `specset specs download <ref> --out specs/`, `specset drawings download <ref> --format pdf --out drawings/`, `specset docs download <ref> --out docs/`, `specset files download <ref> --out inputs/`, or `specset projects hydrate <project> --out . --include specs,drawings,docs` for a whole project. `.specset/manifest.json` records each file's Specset link, version id and checksum; repeating a download is idempotent and replaces a stale version. Findings cite the Specset link, never the local path.
|
|
157
|
+
|
|
158
|
+
With Native tools on and Permissions Auto or Full, the vision tier's document and drawing reads (`examineDrawingSheets`, `examineDocument`, `examineFile` and the like) may also run code to look closer at their attachments: crop a dense detail from the full-resolution file and view it enlarged. Such a read runs in its own scratch directory holding only its attachments (`inputs/attachment-N.png|pdf`), never the run workspace. Its commands are sandboxed: no network, no credentials in their environment, and nothing readable but the system, developer tools, Homebrew (for Python and Pillow) and that directory. Your own temp directory, where other applications keep files, stays closed except, under Claude Code, for the scratch files macOS's `sips` saves there; the shared `/tmp` stays closed. Claude Code's command sandbox denies reading by default, a hook holds its Read tool to the directory, and zsh skips your startup files; Codex runs under a permissions profile that adds only Homebrew and its own binary, with the core environment, so it crops with Pillow and `sips` fails; the runner first checks once that the binary enforces the profile (Codex before 0.157.1 ignores its deny entries), and otherwise runs these reads without code. Code execution needs macOS: on Linux, Claude Code's bubblewrap sandbox leaves the credentials it removes readable to commands through its own process, so these reads run without code there. Its actions are printed in the `agent serve` terminal, because a helper read's actions never reach the conversation. These reads were evaluated on the cloud models without code execution, so treat code-execution results as unevaluated.
|
|
159
|
+
|
|
160
|
+
Files the harness writes under `out/` are the run's deliverables: after each turn that used native tools, and when the run ends, the runner uploads new or changed ones and attaches them to the root thread at their `out/…` path (a re-synced path replaces the earlier attachment). The workspace is removed once its run has ended (checked when the runner starts and stops and every ten minutes) or after seven untouched days; outputs that could not be attached keep the directory for a retry.
|
|
161
|
+
|
|
162
|
+
Sessions are ephemeral (`persistSession: false` for Claude, `ephemeral: true` for Codex): a restarted runner needs a new machine assignment and starts fresh sessions seeded from Specset's transcript. A lost native continuation fails visibly rather than replaying writes or switching to a cloud model. This is a personal runner executing project content as the local OS user, not an OS sandbox: use a separate account or host for untrusted content.
|
|
163
|
+
|
|
164
|
+
### Serve multiple local threads
|
|
165
|
+
|
|
166
|
+
Connect to an organization with `specset agent serve --host <host> --org <slug|id>`; no project or thread is required. Enable **Execute locally** in conversation Settings. A sole eligible connected runner automatically receives your queued local request; with multiple connected runners, choose **Machine** in Settings. The connection command disappears once a machine is connected. Completed, stopped, or expired runs offer **Start a new local run** above the composer; viewing them does not restart them. `--thread <id>` immediately assigns an existing root; `--message "Review electrical coordination" --type DrawingReview --coordinationTaskTypes ElectricalDistribution` creates a local root in the selected project. `--org <slug|id>` pins the org; otherwise the selected org or sole membership on that host is used. Omit `--project` for organization scope, or supply a comma-separated project allowlist. A new message-created thread requires exactly one project. It serves from the accounts `specset harness list` shows (config.yml's `runner:` block, or the logins this shell would use when none are listed); `specset harness add claude2 --harness claude --home ~/.claude2 --preferred` adds another login, and `--account` limits one run. Claude uses the CLI’s bundled SDK runtime, then native `claude` on PATH. Codex uses `CODEX_PATH`, native `codex` on PATH, then the managed native runtime from `specset harness install codex`. Startup checks each account's runtime before registering. Run a separate `serve --host <deployment>` process for each dev worktree. Each process prints and pins its host/org/accounts at startup; later CLI host/org changes cannot redirect it. Login and selected org are stored per host; execution limits apply per runner. For a bounded smoke test, add `--stopAfterIssues 2`; the root counts issues across its children and stops that tree when the threshold is reached (an in-flight batch can exceed it). Only this signed-in user can assign work, and children inherit the same machine, project scope, deadline and thread budget.
|
|
167
|
+
|
|
168
|
+
`agent serve` uses server-owned orchestration: Temporal executes the agent and its tools, while model requests run through the connected machine. This includes generic drawing-coordination assessments, image inputs and structured output. The runner keeps a native session alive across each complete parallel tool batch and sends back the server's authorized results. All Specset approvals remain in the web app; native tools follow the thread's **Native tools** setting (see above) and native delegation stays off. Independent model requests use independent sessions. Claude uses `persistSession: false`; Codex uses `ephemeral: true`.
|
|
169
|
+
|
|
170
|
+
For an unattended kickoff, `--autoApprovePlan` skips the plan sign-off and `--autoApprove` approves Specset tools for that message (default off for `serve`). `--isolateIssues` ignores pre-existing project issues when planning a bounded test. The command prints the created or assigned thread link. File attachments and file tool results preserve bytes, MIME type and optional filename through the same transport. Claude receives raw PDFs; Codex receives server-rendered PDF page images, capped at 20 pages per request across all PDFs. Both support image inputs and UTF-8 text attachments. Other binary formats fail explicitly until a compatible reader or conversion is available.
|
|
171
|
+
|
|
172
|
+
Pin both `--host <deployment>` and `--org <slug>` when using `agent chat`, `agent start`, `agent show`, `agent inspect`, `agent approve` or `agent stop`; these overrides do not change the CLI’s saved selection.
|
|
173
|
+
|
|
174
|
+
Every model call carries its routing tier (conversation, orchestrator, planner, analyst, worker, lite, balanced, query, vision), and each tier names a model that any account whose harness offers it serves. The defaults match the app; `specset harness list` prints each tier's current model and the class it runs as. Antigravity is opt-in: it serves those tiers only after you add an account for it (`specset harness add agy --harness antigravity`); until then they run their model's class on Claude Code or Codex, or in the cloud with `harness fallback`. A model no account offers runs as its class (frontier, standard, fast) on a harness the machine has. Change a tier with `specset harness tier <tier> <model[:effort]>`, a class's model with `specset harness model <harness> <class> <model> [--effort e]`, or one run's with `agent serve --tier conversation=opus`. The conversation's Settings pins a class or one of the reported models per harness for that thread's own steps, plus a reasoning effort; children and helper calls keep the tiers. When the preferred accounts for a model are at their limits, `specset harness failover sameModel|any|off` decides where its calls go (default sameModel: other accounts with the same model; any: also the same class elsewhere); a call that already streamed fails instead and the next one goes elsewhere. A provider rate limit (HTTP 429) is waited out rather than failing the run: the server retries the call once the account's short wait passes (on another account if one has room), unless it already ran a native command or edit, which a retry could repeat; only every account being at its usage limit stops the run. `specset harness fallback <tier|all> cloud` (or `agent serve --fallback analyst=cloud`) sends a tier's calls to Specset's cloud model, billed to the organization, instead of another provider's whenever no account here can serve its model (none offers it, or its accounts are at their limits); `local` is the default. `--concurrency` defaults to 5 (at most 16) and limits active model calls; tool and approval waits release their slot so even 1 can complete nested fan-out. `--maxThreads` defaults to 100 and `--maxRunSeconds` to 3600 per root authorization. `specset harness limits --concurrency 16 --maxThreads 300 --maxRunSeconds 43200` saves them in config.yml for every `agent serve` (a flag still wins for one run; `default` clears one; no flags prints them). Specset’s `--autoApprove` message setting controls tool approval; the thread's Permissions setting bounds native tools when they are on. Ctrl-C revokes the registration and stops queued/running descendants. A restart needs a new assignment. A lost native continuation fails visibly rather than replaying writes or switching to a cloud model.
|
|
175
|
+
|
|
176
|
+
Harness tool callbacks can only wait for results supplied by the server. Each job receives private harness configuration and a minimal environment; with native tools on, that private home also holds a CLI login for the run's host and organization so `specset` works from the harness's shell. Claude shares the selected native credential store and its refresh lock. Codex uses an authentication-only native process to refresh the selected login, then supplies temporary access tokens to isolated inference sessions. Neither copies rotating refresh credentials into job homes. Settings, hooks, plugins and global MCP servers are excluded from inference sessions. Run `claude auth login` first if the harness reports authentication is required. It still runs as the local OS user, not inside an OS sandbox. Use a dedicated account or isolated host for untrusted project content; do not share this personal runner across users.
|
|
177
|
+
|
|
178
|
+
Use `specset agent runners list --json` to inspect your registrations.
|
|
179
|
+
Use `specset agent runners revoke <runner-id>` to stop and revoke one remotely, including an offline runner after a crash.
|
|
@@ -18,8 +18,6 @@ Maintenance has three layers:
|
|
|
18
18
|
- **MaintenancePlan** — a schedule on exactly one Product, Asset, Location, or System. Product plans fan out to installed assets. Its `tiers` are independent schedule items that pair a Procedure with a calendar cadence, meter trigger, or both.
|
|
19
19
|
- **WorkOrder** — a concrete occurrence or ad-hoc job. Generated work orders snapshot their checklist fields, so history remains stable when a Procedure changes.
|
|
20
20
|
|
|
21
|
-
`MaintenanceTask` and its completion API no longer exist. Use Procedure, MaintenancePlan, and WorkOrder operations below.
|
|
22
|
-
|
|
23
21
|
## Discover Before Mutating
|
|
24
22
|
|
|
25
23
|
Input objects evolve, especially checklist fields and plan tiers. Introspect the relevant input before composing a mutation:
|
|
@@ -164,9 +162,158 @@ Other lifecycle operations:
|
|
|
164
162
|
|
|
165
163
|
## Entity Documents and Documentation
|
|
166
164
|
|
|
167
|
-
Location, Product, Company, System, and Warranty link project Documents through entity-specific role-tagged pivots. Read `<entity>Documents(<entity>Id)`, then call `set<Entity>DocumentRoles(<entity>Id, documentId, roles)` after introspecting that entity's role enum.
|
|
165
|
+
Asset, Location, Product, Company, System, and Warranty link project Documents through entity-specific role-tagged pivots. Read `<entity>Documents(<entity>Id)`, then call `set<Entity>DocumentRoles(<entity>Id, documentId, roles)` after introspecting that entity's role enum (`AssetDocumentRole`, `ProductDocumentRole`, `SystemDocumentRole`, `LocationDocumentRole`, `CompanyDocumentRole`, `WarrantyDocumentRole`). The roles array is replaced atomically; an empty role list removes the pivot and may delete the underlying Document when it becomes orphaned. Asset also exposes `deleteAssetDocument(id)`.
|
|
166
|
+
|
|
167
|
+
Attaching a new file is a three-step flow — the same Document can then be linked to several entities (a family IOM shared by every product in the family):
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
CLOUD_FILE=$(specset files upload ./aaon-rn-iom.pdf --type application/pdf --json | jq -r .id)
|
|
171
|
+
specset api --query "mutation { createDocumentsFromCloudFiles(cloudFileIds: [\"$CLOUD_FILE\"], projectId: \"<project-id>\") { id title } }"
|
|
172
|
+
specset api --query 'mutation { updateDocument(id: "<document-id>", title: "AAON RN Series — IOM") { id } }' # title drives lists and PDF bookmarks; the default is the filename
|
|
173
|
+
specset api --query 'mutation { setProductDocumentRoles(productId: "<product-id>", documentId: "<document-id>", roles: [OperationManual, MaintenanceManual]) { id } }'
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Existing project Documents work too — a submittal attachment's `document { id }` (from `paginatedSubmittals … attachments { document { id title } }`) can be linked directly as `SubmittalPackage`/`Datasheet`; the only check is that the Document belongs to the same project. To bind a slice of a large file, `extractPagesFromFileResource(id: <fileResourceId>, pages: [3, 4, 5])` returns a new CloudFile to feed into `createDocumentsFromCloudFiles`. Only PDF files merge into the O&M package export; images and other types are listed as references.
|
|
177
|
+
|
|
178
|
+
Asset, Location, Product, Company, and System also have markdown documentation blocks. `update<Entity>Documentation(id, markdown)` replaces the block; `mark<Entity>DocumentationComplete(id)` attests that it is current. Any later create/update/link on the entity (a new document pivot, a warranty document, a field edit) marks the documentation stale again, so when seeding a graph write documentation **last**. Calling `mark<Entity>DocumentationComplete` with an empty block sets the state to `NotApplicable`, which the package readiness report accepts — use it for entities that don't warrant prose rather than writing filler.
|
|
179
|
+
|
|
180
|
+
### Writing documentation that reads well in the O&M package export
|
|
181
|
+
|
|
182
|
+
The rules below are the same ones the in-app documentation agent follows (they are one shared block; a test keeps this copy in sync).
|
|
183
|
+
|
|
184
|
+
### Where Documentation Renders
|
|
185
|
+
|
|
186
|
+
The documentation block renders on the entity's show page and in the compiled O&M closeout package PDF — a formal handover manual the owner's facilities team keeps for decades. The manual already prints the following from structured data, so documentation never restates it:
|
|
187
|
+
|
|
188
|
+
- Identity: tag, serial number, status, install and commissioning dates, quantity, location path, manufacturer, model, spec section, classification, data-package tier.
|
|
189
|
+
- Warranties: kind, start and expiration dates, duration, claims contact and the terms text.
|
|
190
|
+
- Maintenance schedule: every plan, procedure, frequency, craft and estimated hours, built from the maintenance plan records.
|
|
191
|
+
- Spare parts: name, SKU, manufacturer part number, quantity and vendor, from the part records.
|
|
192
|
+
- Contacts: the responsible company with phone and email, plus a per-system contacts rollup.
|
|
193
|
+
- Linked documents: every datasheet, manual, warranty and report, listed and bound directly behind the entity's page.
|
|
194
|
+
|
|
195
|
+
### What to Write
|
|
196
|
+
|
|
197
|
+
Spend the narrative on what tables cannot say: sequences of operation with real setpoints, startup and shutdown, seasonal and emergency procedures, troubleshooting, safety warnings, cross-system interfaces, and callouts where sources conflict. Describe the equipment, not the records — state how it works and how it is cared for, and fold genuine unknowns into one short "Open Items" list, one line each, without citations. A short block with two real sections beats a full template of filler: omit every section the sources don't genuinely cover, and leaving the block blank is a valid outcome for an entity with nothing to add.
|
|
198
|
+
|
|
199
|
+
Write for the building operator in plain language. Paraphrase manual procedures as proper markdown lists, and fix concatenation artifacts (double periods, misspelled manufacturer names) from sources.
|
|
200
|
+
|
|
201
|
+
Keep the block free of what the manual already prints and of anything that goes stale:
|
|
202
|
+
|
|
203
|
+
- No warranty terms or dates in prose, no frequency lists or task inventories, no tag/serial/model/quantity dossiers, no contractor names or phone numbers, and no parts tables pasted from manuals — replacement-parts data belongs in part records.
|
|
204
|
+
- No claims about the state of the records ("no dates are populated", "this task is recorded on the checklist") — they end up contradicting the printed tables.
|
|
205
|
+
- No restatement of the entity's `description` field as the opening — both print in sequence.
|
|
206
|
+
- No internal vocabulary ("portal", "normalized", "occurrence basis", "identity guard", "MaintenanceTask", "sourceMarkdown"), entity UUIDs, or extraction and slug references.
|
|
207
|
+
- No all-caps sentences or blockquote dumps of manual text, and no sections whose only content is "not established in reviewed source" or "see the linked manual".
|
|
208
|
+
|
|
209
|
+
### Citations
|
|
210
|
+
|
|
211
|
+
Citations are clickable in the app and plain text in the printed manual, so keep them sparse and short: at most one per section, placed at the end of the claim it supports, as a markdown link whose display text is a short label such as "Siemens O&M p. 712" or "Warranty Table p. 5". Use citation URLs exactly as returned by the tools. The entity's bound-documents list already anchors provenance, so there are no per-sentence citations, multi-citation parentheticals, full source filenames, paragraph numbers, spreadsheet cell references, or dedicated "Source:" lines (print strips those).
|
|
212
|
+
|
|
213
|
+
### Headings
|
|
214
|
+
|
|
215
|
+
The entity name renders as the page title, the block is embedded under a "Documentation" heading on the show page, and it may be re-rendered inside a parent entity's hierarchical view, so heading levels must compose:
|
|
216
|
+
|
|
217
|
+
- Top-level sections use `##`; sub-sections use `###`, then `####`, without skipping levels.
|
|
218
|
+
- Begin with the first content section (for example `## Description`). The entity's own name is never a heading and `#` is never used — that level is the page title, and a leading H1 matching the entity name is suppressed in print.
|
|
219
|
+
- Keep section names consistent with the templates below so sibling entities render with the same structure.
|
|
220
|
+
|
|
221
|
+
### Section Templates
|
|
222
|
+
|
|
223
|
+
Use these section orderings with the operator-facing names shown; most entities warrant only one to three of them.
|
|
224
|
+
|
|
225
|
+
**Product** — the canonical home for manufacturer operating knowledge. A product with any linked submittal, datasheet, manual or warranty document gets a block; only a product with no linked source documents is left blank. Location and system blocks may roll product knowledge up but never replace it.
|
|
226
|
+
|
|
227
|
+
```markdown
|
|
228
|
+
## Description (1-3 sentences: what it is and its role — not metadata)
|
|
229
|
+
## Operation (sequence of operation, setpoints, modes, interlocks)
|
|
230
|
+
## Routine Maintenance (procedure steps and precautions — never frequencies; the schedule table prints those)
|
|
231
|
+
## Troubleshooting
|
|
232
|
+
## Safety
|
|
233
|
+
## Open Items
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**System** — the system in its own words, spanning multiple products. A parent system covers only what is true of the whole (shared operation, shared safety): the manual prints the subsystems list and rolls up schedules, warranties and contacts, so content common to sibling systems lives once on the parent and each child gets at most one sentence of scope.
|
|
237
|
+
|
|
238
|
+
```markdown
|
|
239
|
+
## Description (what the system is and its boundary, 2-4 sentences)
|
|
240
|
+
## Sequence of Operation
|
|
241
|
+
## Interfaces (only real cross-system relationships: what feeds, releases, or controls what)
|
|
242
|
+
## Seasonal & Emergency Procedures
|
|
243
|
+
## Troubleshooting
|
|
244
|
+
## Safety
|
|
245
|
+
## Open Items
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
**Location** — building or area overview.
|
|
249
|
+
|
|
250
|
+
```markdown
|
|
251
|
+
## Description
|
|
252
|
+
## Access & Safety
|
|
253
|
+
## Open Items
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**Asset** — installation-specific facts only; most assets need very little.
|
|
257
|
+
|
|
258
|
+
```markdown
|
|
259
|
+
## As-Installed Configuration (field settings, orientations, connections not captured by structured fields)
|
|
260
|
+
## Commissioning Notes
|
|
261
|
+
## Open Items
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
**Company** — only what the contacts block cannot carry.
|
|
265
|
+
|
|
266
|
+
```markdown
|
|
267
|
+
## Escalation
|
|
268
|
+
## Supplier Portal
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Example (Product)
|
|
272
|
+
|
|
273
|
+
```markdown
|
|
274
|
+
## Description
|
|
275
|
+
Passive rubber check valves preventing backflow from rivers, oceans, and storm water into outfall lines.
|
|
276
|
+
|
|
277
|
+
## Operation
|
|
278
|
+
Flow opens the bill section; back-pressure closes it. No power or operator action required. Do not exceed 25 psi back-pressure [Manual p. 3](sb://doc/...).
|
|
279
|
+
|
|
280
|
+
## Routine Maintenance
|
|
281
|
+
1. Clear debris from the bill opening.
|
|
282
|
+
2. Inspect the elastomer for cuts or abrasion; replace on any through-cut.
|
|
283
|
+
|
|
284
|
+
## Troubleshooting
|
|
285
|
+
Standing water upstream usually means debris is holding the bill open — clear before assuming valve failure.
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## Parts and Meter Readings
|
|
289
|
+
|
|
290
|
+
`createPart(input: { projectId, name, sku, manufacturerPartNumber, unit, quantity, minQuantity, maxQuantity, unitCost, stocked, bin, vendorId, assetLinks: [{ assetId, quantity }] })` creates a stocked part with its per-asset quantities; `createPartMovement(input: { partId, quantity, note })` records receipts (positive) and consumption (negative), and `countedQuantity` records a cycle count. Read with `paginatedParts(projectId, filters)`.
|
|
291
|
+
|
|
292
|
+
`logMeterReading(assetId, unit: Hours|Cycles, value, readAt)` records a runtime or cycle reading; meter-triggered plan tiers (`meterUnit`/`meterThreshold`) generate work from these. `meterReadings(assetId, unit, limit)` lists them.
|
|
293
|
+
|
|
294
|
+
## Closeout Packages (O&M manual export)
|
|
295
|
+
|
|
296
|
+
A closeout package compiles the graph into one bookmarked PDF: front matter (cover, directory, warranty log, hyperlinked TOC), a slip sheet and overview per system (or location), a data page per asset, and every linked PDF document bound behind its owner (each unique file once). Scope is `Project` (everything), `Systems`, `Assets`, or `Locations` with `targetIds`; `orderingAxis` is `System` (default) or `Location`.
|
|
297
|
+
|
|
298
|
+
Check readiness first — it is deterministic and the same builder the compile uses, so a clean report means a clean manual:
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
specset api --query '{ closeoutPackageReadiness(projectId: "<project-id>", scopeKind: Project) { warningCount warnings } }'
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Warning kinds and how to clear them: `DocumentationMissing`/`DocumentationOutdated` (write or mark documentation complete on the named Asset/Product/System/Location), `AssetFieldMissing` (serial number or install date), `WarrantyMissing` (every asset needs at least one Warranty), `ProductManualMissing` (each Product needs an `OperationManual` or `MaintenanceManual` document), `PlanWithoutProcedure` (a plan with no tiers), `AttachmentNotMergeable` (non-PDF), `TargetDeleted`. `EmptyScope` blocks creation.
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
specset api --query 'mutation { createCloseoutPackageExport(input: { projectId: "<project-id>", scopeKind: Project, orderingAxis: System, includeAttachments: true, title: "… O&M Manual" }) { id workflow { status } } }'
|
|
308
|
+
specset api --query '{ closeoutPackageExport(id: "<export-id>") { completedAt warnings workflow { status progress error } fileResource { id name } } }'
|
|
309
|
+
specset files download <file-resource-id> --out manual.pdf # once workflow.status is Completed
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
`paginatedCloseoutPackageExports(projectId)` lists prior exports; exports are immutable records — regenerate by creating a new one; `deleteCloseoutPackageExport(id)` removes one and its file. In the app the same flow lives under the project's Closeout → Packages page.
|
|
313
|
+
|
|
314
|
+
## Enabling closeout
|
|
168
315
|
|
|
169
|
-
|
|
316
|
+
`CloseoutAuthService.isCloseoutActive` requires the org's closeout SKU **and** (unless the org is in `fmMode`) the project's closeout toggle. Specset staff turn both on; when closeout operations report closeout as inactive, ask your Specset contact to enable it.
|
|
170
317
|
|
|
171
318
|
## Dedup / Re-pointing
|
|
172
319
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: specset-issues
|
|
3
|
+
description: Use when working with a Specset project's design-review issues from the CLI — listing the queue by severity, tier, or verification state, and reading each issue's verdict.
|
|
4
|
+
allowed-tools: Bash Read AskUserQuestion
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Specset Issues
|
|
8
|
+
|
|
9
|
+
Design reviews (Design Review, Drawing Review, Design Quality Review, Project Review) and issue-finding skills file **issues** on a project. Each issue can be **verified** by an adversarial agent that re-reads the cited sheets and sections and records a verdict — `Confirmed` or `Rejected` — with a short justification. New review issues are verified automatically; skill-run issues, issues filed before verification existed, and issues whose runs ended without a verdict are verified on demand.
|
|
10
|
+
|
|
11
|
+
## Reading the queue
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
specset issues list --project <projectId> # active, non-Cleanup issues
|
|
15
|
+
specset issues list --project <projectId> --severity High,Medium --notVerified --limit 500
|
|
16
|
+
specset issues list --project <projectId> --thread <reviewThreadId> --json # one review's findings
|
|
17
|
+
specset issues list --project <projectId> --thread <runThreadId> --org <slug> # a skill run, by the id agent chat printed
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
- `--severity` takes a comma list (`High`, `Medium`, `Low`); `--notVerified` keeps only issues with no verdict; `--archived` switches to the archived set.
|
|
21
|
+
- `--thread` matches the thread and every review thread under it: a skill's issues belong to its delegated review, so the run id `specset agent chat` prints finds them directly. `--org` pins the organization like the other commands.
|
|
22
|
+
- Cleanup-tier issues (real but self-resolving, kept out of the review queue) are excluded unless you pass `--includeCleanup` — the same rule the app's default queue uses.
|
|
23
|
+
- The table shows `#number severity tier verdict title`; `verdict` is `Confirmed`, `Rejected`, `verifying` (run in flight) or `unverified`. `--json` returns the full rows including the originating review thread.
|
|
24
|
+
|
|
25
|
+
## Verification
|
|
26
|
+
|
|
27
|
+
Verdicts come from the app's own verification runs: new review issues are verified automatically, and a member can start verification for an individual issue from the issue in the app. `specset issues list` shows the verdict on every row (`--notVerified` to find the ones still waiting).
|