@zeyos/client 0.3.0 → 0.5.0
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/CHANGELOG.md +54 -0
- package/README.md +41 -2
- package/agents/README.md +10 -0
- package/agents/shared/zeyos-agent-operating-guide.md +42 -0
- package/agents/shared/zeyos-entity-map.md +5 -1
- package/agents/shared/zeyos-entity-reference.md +89 -33
- package/agents/shared/zeyos-query-patterns.md +26 -0
- package/agents/zeyos-calendar-and-scheduling/SKILL.md +45 -0
- package/agents/zeyos-calendar-and-scheduling/references/workflows.md +49 -0
- package/agents/zeyos-data-quality-and-governance/SKILL.md +43 -0
- package/agents/zeyos-data-quality-and-governance/references/workflows.md +51 -0
- package/agents/zeyos-document-and-approval/SKILL.md +41 -0
- package/agents/zeyos-document-and-approval/references/workflows.md +43 -0
- package/agents/zeyos-procurement-and-supplier-performance/SKILL.md +36 -0
- package/agents/zeyos-procurement-and-supplier-performance/references/workflows.md +46 -0
- package/agents/zeyos-time-tracking/SKILL.md +2 -0
- package/agents/zeyos-time-tracking/references/workflows.md +68 -0
- package/agents/zeyos-work-management/SKILL.md +4 -3
- package/agents/zeyos-work-management/references/workflows.md +39 -1
- package/docs/03-cli/02-commands.md +36 -2
- package/docs/03-cli/03-configuration.md +1 -0
- package/docs/06-okf/01-overview.md +70 -0
- package/docs/06-okf/02-producing-and-consuming.md +46 -0
- package/docs/06-okf/03-keeping-fresh.md +53 -0
- package/docs/06-okf/04-loops.md +58 -0
- package/docs/06-okf/_category_.json +9 -0
- package/okf/concepts/calendar-timezones.md +10 -0
- package/okf/concepts/confirmation-and-side-effects.md +14 -0
- package/okf/concepts/counting-and-sums.md +10 -0
- package/okf/concepts/currency-and-rounding.md +10 -0
- package/okf/concepts/dates-unix-seconds.md +12 -0
- package/okf/concepts/enums.md +14 -0
- package/okf/concepts/filters-vs-filter.md +14 -0
- package/okf/concepts/idempotency-and-deduplication.md +10 -0
- package/okf/concepts/index.md +16 -0
- package/okf/concepts/null-empty-missing.md +10 -0
- package/okf/concepts/official-versus-latest.md +10 -0
- package/okf/concepts/operationid-vocabulary.md +17 -0
- package/okf/concepts/ownership-versus-attention.md +15 -0
- package/okf/concepts/untrusted-business-content.md +10 -0
- package/okf/concepts/visibility-column.md +13 -0
- package/okf/entities/accounts.md +82 -0
- package/okf/entities/actionsteps.md +84 -0
- package/okf/entities/addresses.md +50 -0
- package/okf/entities/applicationassets.md +43 -0
- package/okf/entities/applications.md +62 -0
- package/okf/entities/appointments.md +79 -0
- package/okf/entities/associations.md +41 -0
- package/okf/entities/binfiles.md +32 -0
- package/okf/entities/campaigns.md +66 -0
- package/okf/entities/categories.md +55 -0
- package/okf/entities/channels.md +54 -0
- package/okf/entities/comments.md +44 -0
- package/okf/entities/components.md +46 -0
- package/okf/entities/contacts.md +96 -0
- package/okf/entities/contacts2contacts.md +42 -0
- package/okf/entities/contracts.md +83 -0
- package/okf/entities/couponcodes.md +58 -0
- package/okf/entities/coupons.md +69 -0
- package/okf/entities/customfields.md +59 -0
- package/okf/entities/davservers.md +74 -0
- package/okf/entities/devices.md +65 -0
- package/okf/entities/documents.md +76 -0
- package/okf/entities/dunning.md +82 -0
- package/okf/entities/dunning2transactions.md +46 -0
- package/okf/entities/entities2channels.md +42 -0
- package/okf/entities/events.md +57 -0
- package/okf/entities/feedservers.md +67 -0
- package/okf/entities/files.md +50 -0
- package/okf/entities/follows.md +40 -0
- package/okf/entities/forks.md +54 -0
- package/okf/entities/groups.md +48 -0
- package/okf/entities/groups2users.md +44 -0
- package/okf/entities/index.md +93 -0
- package/okf/entities/invitations.md +53 -0
- package/okf/entities/items.md +95 -0
- package/okf/entities/ledgers.md +56 -0
- package/okf/entities/likes.md +40 -0
- package/okf/entities/links.md +70 -0
- package/okf/entities/mailinglists.md +67 -0
- package/okf/entities/mailingrecipients.md +45 -0
- package/okf/entities/mailservers.md +77 -0
- package/okf/entities/messagereads.md +40 -0
- package/okf/entities/messages.md +104 -0
- package/okf/entities/notes.md +73 -0
- package/okf/entities/objects.md +70 -0
- package/okf/entities/opportunities.md +87 -0
- package/okf/entities/participants.md +52 -0
- package/okf/entities/payments.md +76 -0
- package/okf/entities/permissions.md +46 -0
- package/okf/entities/pricelists.md +70 -0
- package/okf/entities/pricelists2accounts.md +46 -0
- package/okf/entities/prices.md +49 -0
- package/okf/entities/projects.md +72 -0
- package/okf/entities/records.md +75 -0
- package/okf/entities/relateditems.md +43 -0
- package/okf/entities/resources.md +55 -0
- package/okf/entities/services.md +64 -0
- package/okf/entities/stocktransactions.md +72 -0
- package/okf/entities/storages.md +56 -0
- package/okf/entities/suppliers.md +51 -0
- package/okf/entities/tasks.md +86 -0
- package/okf/entities/tickets.md +86 -0
- package/okf/entities/transactions.md +118 -0
- package/okf/entities/users.md +66 -0
- package/okf/entities/weblets.md +66 -0
- package/okf/index.md +11 -0
- package/okf/log.md +4 -0
- package/okf/metrics/account-address-completeness.md +10 -0
- package/okf/metrics/cash-received.md +10 -0
- package/okf/metrics/index.md +9 -0
- package/okf/metrics/invoiced-net-revenue.md +16 -0
- package/okf/metrics/open-customers.md +14 -0
- package/okf/metrics/overdue-receivables.md +12 -0
- package/okf/metrics/stock-movement-by-storage.md +10 -0
- package/okf/metrics/supplier-delivery-performance.md +10 -0
- package/okf/playbooks/activity-timeline.md +11 -0
- package/okf/playbooks/calendar-availability.md +11 -0
- package/okf/playbooks/campaign-recipient-coverage.md +12 -0
- package/okf/playbooks/customer-360.md +12 -0
- package/okf/playbooks/document-approval.md +10 -0
- package/okf/playbooks/duplicate-account-review.md +11 -0
- package/okf/playbooks/effective-customer-price.md +11 -0
- package/okf/playbooks/index.md +13 -0
- package/okf/playbooks/missing-billing-addresses.md +12 -0
- package/okf/playbooks/revenue-this-year.md +19 -0
- package/okf/playbooks/supplier-scorecard.md +10 -0
- package/okf/playbooks/ticket-work-packet.md +11 -0
- package/package.json +11 -3
- package/scripts/data/okf-curation.mjs +446 -0
- package/scripts/generate-client.mjs +4 -275
- package/scripts/generate-okf.mjs +241 -0
- package/scripts/lib/live-test-config.mjs +20 -0
- package/scripts/lib/okf.mjs +272 -0
- package/scripts/lib/spec-model.mjs +325 -0
- package/src/index.js +4 -0
- package/src/runtime/okf.js +237 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Data Quality and Governance Workflows
|
|
2
|
+
|
|
3
|
+
## Duplicate-account detection (deterministic scoring)
|
|
4
|
+
|
|
5
|
+
1. Pull the active population:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
zeyos list accounts --filter '{"type":1,"visibility":0}' \
|
|
9
|
+
--fields ID,customernum,lastname,firstname --limit 10000 --json
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
2. Normalize comparison keys (lowercase, trim, collapse whitespace) but keep originals.
|
|
13
|
+
3. Score candidate pairs with a published, deterministic policy:
|
|
14
|
+
|
|
15
|
+
| Evidence | Weight | Confidence |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| Exact `customernum` | 1.0 | high |
|
|
18
|
+
| Exact normalized email (via `contacts`) | 0.9 | high |
|
|
19
|
+
| Exact normalized name + address | 0.8 | high |
|
|
20
|
+
| Near name only (edit distance) | 0.4 | low |
|
|
21
|
+
|
|
22
|
+
4. Sort pairs by score descending; emit `{accountA, accountB, score, reasons, confidence}`.
|
|
23
|
+
A clearly different account is not a candidate. Shared generic email domains and similar
|
|
24
|
+
names are never conclusive on their own.
|
|
25
|
+
|
|
26
|
+
## Completeness gaps (anti-join)
|
|
27
|
+
|
|
28
|
+
"Customers missing a billing address": list customers, list `addresses` of `type: 1`
|
|
29
|
+
(billing), keep customers with no matching `account`. `addresses` has **no** `visibility`
|
|
30
|
+
column — do not filter it. State whether you treat empty string, null and missing the same
|
|
31
|
+
(R-020); by default they are distinct.
|
|
32
|
+
|
|
33
|
+
## Remediation is a preview, not an action
|
|
34
|
+
|
|
35
|
+
A "clean up duplicates" request returns:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{ "executed": false,
|
|
39
|
+
"candidates": [ { "accountA": 1, "accountB": 2 } ],
|
|
40
|
+
"proposedActions": [ { "accountId": 2, "action": "archive (needs human review)" } ] }
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Never delete, archive or merge from this analysis (R-009, R-011, R-023). Each action is a
|
|
44
|
+
human decision on an exact ID. Re-query only after an approved, bounded change.
|
|
45
|
+
|
|
46
|
+
## Common failure modes
|
|
47
|
+
|
|
48
|
+
- Treating a fuzzy name match as a confirmed duplicate.
|
|
49
|
+
- Collapsing null / empty / zero into one bucket without saying so.
|
|
50
|
+
- Executing a bulk archive/delete from a "clean up" instruction.
|
|
51
|
+
- Filtering `visibility` on `addresses` (no such column → HTTP 400).
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: zeyos-document-and-approval
|
|
3
|
+
description: Find formal ZeyOS documents, judge draft/final/obsolete status, run approval and finalization gates, and compare notes against formal SOPs. Use when status transitions, approval authority, version choice or formal file artifacts matter ("find the current approved onboarding SOP", "which contracts await approval", "make document 812 final", "compare the draft with the final version"). For lightweight note retrieval use zeyos-notes-and-sops.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# ZeyOS Document and Approval
|
|
7
|
+
|
|
8
|
+
Read [../shared/zeyos-agent-operating-guide.md](../shared/zeyos-agent-operating-guide.md) and [../shared/zeyos-query-patterns.md](../shared/zeyos-query-patterns.md) first. See the OKF `concepts/official-versus-latest` concept and the `playbooks/document-approval` playbook.
|
|
9
|
+
|
|
10
|
+
> **Status, not freshness, decides authority.** The newest artifact is not necessarily the
|
|
11
|
+
> current official one. Retrieve content before claiming what a document says.
|
|
12
|
+
|
|
13
|
+
Primary entities: `documents` (`listDocuments`, `getDocument`, `createDocument`, `updateDocument`), `notes` (`listNotes`, `getNote`), `binfiles` (`listBinFiles`), `files`, plus `users`/`groups` for approval context. Document `status`: 0 DRAFT, 1 FEEDBACKREQUIRED, 2 INREVISION, 3 AWAITINGAPPROVAL, 4 FINAL, 5 OBSOLETE.
|
|
14
|
+
|
|
15
|
+
Typical prompts:
|
|
16
|
+
|
|
17
|
+
- "Find the current approved onboarding SOP."
|
|
18
|
+
- "Which contracts are awaiting approval?"
|
|
19
|
+
- "Compare the draft with the final version."
|
|
20
|
+
- "Make document 812 final."
|
|
21
|
+
|
|
22
|
+
## Workflow
|
|
23
|
+
|
|
24
|
+
1. Search formal `documents` first for "official", "approved", "final" or "current".
|
|
25
|
+
2. Select by **status plus freshness** — a FINAL document outranks a newer OBSOLETE one and a draft note (R-018).
|
|
26
|
+
3. Retrieve binary/file content (`binfile`/`files`) before claiming its contents.
|
|
27
|
+
4. Keep `notes` (lightweight) and `documents` (formal) as separate sources; do not silently merge conflicting sources (surface the conflict, name the authoritative source).
|
|
28
|
+
5. For finalization/approval: fetch the exact ID + current status, show a preview and any naming conflict, require exact confirmation, `updateDocument` one ID, then re-read and report old/new status (R-005, R-006, R-011).
|
|
29
|
+
|
|
30
|
+
## Routing boundaries
|
|
31
|
+
|
|
32
|
+
- Note-centric retrieval/summarization → `zeyos-notes-and-sops`.
|
|
33
|
+
- Use this skill when status transitions, approval authority, version choice or formal files matter.
|
|
34
|
+
|
|
35
|
+
## Safety
|
|
36
|
+
|
|
37
|
+
- FINAL, APPROVED, OBSOLETE and cancellation transitions are high impact (R-011).
|
|
38
|
+
- Never approve on behalf of an unidentified user/group.
|
|
39
|
+
- Never bulk-finalize or bulk-obsolete documents (R-009).
|
|
40
|
+
- Never overwrite a binary file without an explicit target and confirmation.
|
|
41
|
+
- Preserve provenance and revision identifiers in summaries.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Document and Approval Workflows
|
|
2
|
+
|
|
3
|
+
## Select the current official artifact
|
|
4
|
+
|
|
5
|
+
1. Query formal `documents` matching the topic; read `status`, `name`, `documentnum`, `filename`.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
zeyos list documents --filter '{"visibility":0,"name":{"~~*":"onboarding%"}}' \
|
|
9
|
+
--fields ID,name,status,filename,documentnum --limit 100 --json
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
2. Rank by authority, not date: prefer `status = 4` (FINAL). A newer `status = 5`
|
|
13
|
+
(OBSOLETE) does **not** win, and a draft `note` is only fallback context (R-018).
|
|
14
|
+
3. State the selection reason (which status, why it outranks the alternatives).
|
|
15
|
+
|
|
16
|
+
## Compare a note against a formal SOP
|
|
17
|
+
|
|
18
|
+
Retrieve the actual text of both (`notes.text`; `documents.description`/binary content).
|
|
19
|
+
Report agreements and conflicts explicitly; never synthesize a single answer that hides a
|
|
20
|
+
contradiction. The formal FINAL document is the authoritative source.
|
|
21
|
+
|
|
22
|
+
## Finalization / approval gate
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# 1. Fetch exact target + current status
|
|
26
|
+
zeyos get document <id> --json
|
|
27
|
+
# 2. Preview the change (no write) and surface any same-name conflict
|
|
28
|
+
zeyos update document <id> --query --status 4
|
|
29
|
+
# 3. Only after explicit confirmation of the exact ID:
|
|
30
|
+
zeyos update document <id> --status 4
|
|
31
|
+
# 4. Re-read and report old/new status
|
|
32
|
+
zeyos get document <id> --fields ID,name,status --json
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Update exactly one ID. Never fuzzy-match a name to a set of documents and finalize them in
|
|
36
|
+
bulk (R-009, R-011). Leave similarly-named documents untouched.
|
|
37
|
+
|
|
38
|
+
## Common failure modes
|
|
39
|
+
|
|
40
|
+
- Picking the newest artifact instead of the FINAL one.
|
|
41
|
+
- Claiming document contents without retrieving the file/binary.
|
|
42
|
+
- Bulk-finalizing by fuzzy name match.
|
|
43
|
+
- Approving without identifying the approver / authority.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: zeyos-procurement-and-supplier-performance
|
|
3
|
+
description: Compare suppliers, analyze procurement orders/deliveries/invoices, lead times, price variance and reorder worklists in ZeyOS. Use for "which supplier is best for 20 units of item ABC", "which purchase orders are late", "compare supplier delivery performance", "where did procurement prices exceed the order". Read-only analysis — never place, book, cancel or transmit a procurement transaction.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# ZeyOS Procurement and Supplier Performance
|
|
7
|
+
|
|
8
|
+
Read [../shared/zeyos-agent-operating-guide.md](../shared/zeyos-agent-operating-guide.md) and [../shared/zeyos-query-patterns.md](../shared/zeyos-query-patterns.md) first. See the OKF `playbooks/supplier-scorecard` playbook and `metrics/supplier-delivery-performance` metric.
|
|
9
|
+
|
|
10
|
+
> **Keep ordered, delivered and invoiced quantities/values distinct**, and state the
|
|
11
|
+
> ranking policy before you rank. Analysis is read-only.
|
|
12
|
+
|
|
13
|
+
Primary entities: `transactions` types **5 PROCUREMENT_REQUEST, 6 ORDER, 7 DELIVERY, 8 INVOICE, 9 CREDIT** (`listTransactions`), `suppliers` (item↔supplier links: `listSuppliers`), `items`, `accounts` (the supplier), `stocktransactions`, `storages`, `payments`, and `contracts` where supplier agreements matter. `transactions` has **no** `visibility` column.
|
|
14
|
+
|
|
15
|
+
Typical prompts:
|
|
16
|
+
|
|
17
|
+
- "Which supplier is best for 20 units of item ABC?"
|
|
18
|
+
- "Which purchase orders are late?"
|
|
19
|
+
- "Compare supplier delivery performance."
|
|
20
|
+
- "Where did procurement prices exceed the order?"
|
|
21
|
+
|
|
22
|
+
## Workflow
|
|
23
|
+
|
|
24
|
+
1. Resolve the item and the supplier `accounts` (type 2 SUPPLIER).
|
|
25
|
+
2. For sourcing decisions, read `suppliers` links: `price`, `minamount`, `deliverytime`, `stock`.
|
|
26
|
+
3. Apply the order quantity: a supplier is eligible only if `minamount <= quantity` — never hide a minimum-quantity constraint (R-003).
|
|
27
|
+
4. State the ranking policy first (e.g. eligible, then price ascending, then delivery time), then rank.
|
|
28
|
+
5. For performance, keep ordered (type 6), delivered (type 7) and invoiced (type 8) values separate; compute price variance as invoiced − ordered.
|
|
29
|
+
6. Compute only over a declared time window and one currency (R-014, R-019). Exclude cancelled records by documented status policy.
|
|
30
|
+
7. Label reorder advice as heuristic unless a formal stock policy exists.
|
|
31
|
+
|
|
32
|
+
## Safety
|
|
33
|
+
|
|
34
|
+
- Never place, approve, book, cancel or transmit a procurement transaction automatically (R-010, R-011).
|
|
35
|
+
- Never change supplier master data or price lists from an analytical request.
|
|
36
|
+
- Any future write workflow requires exact supplier, item, quantity, currency and confirmation.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Procurement and Supplier Performance Workflows
|
|
2
|
+
|
|
3
|
+
## Procurement transaction types
|
|
4
|
+
|
|
5
|
+
`transactions.type`: 5 PROCUREMENT_REQUEST, 6 PROCUREMENT_ORDER, 7 PROCUREMENT_DELIVERY,
|
|
6
|
+
8 PROCUREMENT_INVOICE, 9 PROCUREMENT_CREDIT. (Billing types 0–4 are a different domain.)
|
|
7
|
+
`transactions` has **no** `visibility` column — do not add `"visibility":0`.
|
|
8
|
+
|
|
9
|
+
## Supplier comparison for an order quantity
|
|
10
|
+
|
|
11
|
+
1. Resolve the item, then read its supplier links:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
zeyos list suppliers --filter '{"item":<itemId>}' \
|
|
15
|
+
--fields ID,account,price,minamount,deliverytime,stock --limit 1000 --json
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
2. Resolve each `account` to a supplier name.
|
|
19
|
+
3. Eligibility: `minamount <= orderQuantity`. State eligibility explicitly — never drop a
|
|
20
|
+
supplier silently because of its minimum.
|
|
21
|
+
4. Ranking policy (declare before ranking): eligible first, then `price` ascending, then
|
|
22
|
+
`deliverytime` ascending. Report `rank` and `eligible` per option.
|
|
23
|
+
|
|
24
|
+
## Supplier scorecard over a period
|
|
25
|
+
|
|
26
|
+
Group procurement `transactions` by supplier `account` within a declared window + currency:
|
|
27
|
+
|
|
28
|
+
- `ordered_value` = Σ `netamount` where type 6
|
|
29
|
+
- `invoiced_value` = Σ `netamount` where type 8
|
|
30
|
+
- `price_variance` = invoiced_value − ordered_value
|
|
31
|
+
- delivery timing from type 7 dates vs the order `duedate` (on-time when delivered by duedate)
|
|
32
|
+
|
|
33
|
+
Keep all values in one currency (R-019); exclude cancelled records per documented policy.
|
|
34
|
+
|
|
35
|
+
## Reorder advice
|
|
36
|
+
|
|
37
|
+
Label reorder suggestions as heuristic unless the instance has a formal stock policy
|
|
38
|
+
(min/max levels). Combine `stocktransactions` net-booked stock by `storages` with supplier
|
|
39
|
+
`deliverytime` to flag at-risk items — but present it as advice, not an action.
|
|
40
|
+
|
|
41
|
+
## Common failure modes
|
|
42
|
+
|
|
43
|
+
- Mixing billing types (0–4) with procurement types (5–9).
|
|
44
|
+
- Hiding a minimum-order-quantity constraint when ranking.
|
|
45
|
+
- Conflating ordered, delivered and invoiced values.
|
|
46
|
+
- Summing across currencies.
|
|
@@ -15,6 +15,7 @@ Typical prompts:
|
|
|
15
15
|
- "Record 2 hours on ticket 812." / "Book 90 minutes against Project Atlas."
|
|
16
16
|
- "Log half an hour for ACME, I was on a call about the renewal."
|
|
17
17
|
- "How much time did I log this week?" / "Summarize my logged hours by account."
|
|
18
|
+
- "Give me a summary of logged ticket time from the last four weeks."
|
|
18
19
|
- "Actually make that 90 minutes, not 60." / "Move that time to ticket 813."
|
|
19
20
|
|
|
20
21
|
## Two jobs
|
|
@@ -44,5 +45,6 @@ Interactivity here means **act first, then ask only when real data is ambiguous*
|
|
|
44
45
|
## Output discipline
|
|
45
46
|
|
|
46
47
|
- For "my work": state the resolved user and the open-status definition you used, then the list.
|
|
48
|
+
- For ticket time summaries: include both actionsteps directly linked by `actionstep.ticket` and actionsteps linked by `actionstep.task` where `task.ticket` is the summarized ticket; dedupe by actionstep ID before summing.
|
|
47
49
|
- For a logged entry: report the created actionstep id, the attached record (ticket/task/account), the effort in minutes, and the date.
|
|
48
50
|
- Separate what you resolved from what you assumed; call out any account or work-item ambiguity you had to break.
|
|
@@ -17,6 +17,7 @@ See [../../shared/zeyos-entity-reference.md](../../shared/zeyos-entity-reference
|
|
|
17
17
|
|
|
18
18
|
- **Time entries are `actionsteps`.** The `effort` field is **minutes** (integer). There is no separate time-entry resource.
|
|
19
19
|
- **Actionstep foreign keys:** `task`, `ticket`, `account`, `transaction` — plus `assigneduser`, `date`, `duedate`, `status`, `effort`. **There is no `project` FK on an actionstep**, so project-level time attaches through a ticket/task in that project, or to the project's `account`.
|
|
20
|
+
- **Ticket time rollups cross the task layer.** For "logged ticket time", count actionsteps with `ticket = <ticketId>` and actionsteps with `task = <taskId>` where that task has `ticket = <ticketId>`. Always dedupe by actionstep `ID` before summing in case a row carries both FKs.
|
|
20
21
|
- **Actionstep status:** `0` DRAFT · `1` COMPLETED · `2` CANCELLED · `3` BOOKED. Log already-done work as **COMPLETED (1)**; use **BOOKED (3)** only when the instance treats booked effort as the billed/locked record and the user says so.
|
|
21
22
|
- **Ticket/task status:** `0` NOT_STARTED · `1` AWAITING_ACCEPTANCE · `2` ACCEPTED · `3` REJECTED · `4` ACTIVE · `5` INACTIVE · `6` FEEDBACK_REQUIRED · `7` TESTING · `8` CANCELLED · `9` COMPLETED · `10` FAILED · `11` BOOKED. Treat **open/current = status `!IN [8,9,10,11]`** (exclude cancelled/completed/failed/booked). State this definition in the answer; the user can narrow it (e.g. only `4` ACTIVE).
|
|
22
23
|
- **Foreign keys per resource:** `tickets` carry `account`, `project`, `assigneduser`; `tasks` carry `ticket`, `project`, `assigneduser` (no `account` — reach the account through the task's ticket/project); `projects` carry `account`, `assigneduser`; `accounts` carry `lastname`, `firstname`, `customernum` (no `name` field).
|
|
@@ -195,6 +196,72 @@ const totalMinutes = rows.reduce((sum, r) => sum + (Number(r.effort) || 0), 0);
|
|
|
195
196
|
|
|
196
197
|
4. Sum `effort` as minutes; convert to hours only if asked. To break down "by account/ticket", group the rows by the FK and resolve the account/ticket names with a second query. Report the total and the breakdown, and state the window and status set you used.
|
|
197
198
|
|
|
199
|
+
## Pattern: "Give me a summary of logged ticket time from the last four weeks"
|
|
200
|
+
|
|
201
|
+
Use this whenever the user asks for ticket time, ticket hours, support time by ticket, or a ticket-level timesheet summary. A time entry can be attached directly to a ticket or indirectly to a task that belongs to a ticket; both are ticket time.
|
|
202
|
+
|
|
203
|
+
1. Resolve the date window to Unix seconds and count only `actionsteps.status IN [1,3]` unless the user explicitly asks for drafts/open follow-ups.
|
|
204
|
+
2. If the user named a specific ticket, resolve it first, then query:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
# direct ticket time
|
|
208
|
+
zeyos list actionsteps \
|
|
209
|
+
--fields ID,name,effort,date,status,ticket,task,assigneduser \
|
|
210
|
+
--filter '{"ticket":<ticketId>,"status":{"IN":[1,3]},"date":{">=":<start>,"<=":<end>}}' \
|
|
211
|
+
--limit 10000 --json
|
|
212
|
+
|
|
213
|
+
# tasks that belong to the ticket; do not filter task status for historical time
|
|
214
|
+
zeyos list tasks \
|
|
215
|
+
--fields ID,tasknum,name,ticket \
|
|
216
|
+
--filter '{"ticket":<ticketId>}' \
|
|
217
|
+
--limit 10000 --json
|
|
218
|
+
|
|
219
|
+
# time logged on those tasks
|
|
220
|
+
zeyos list actionsteps \
|
|
221
|
+
--fields ID,name,effort,date,status,ticket,task,assigneduser \
|
|
222
|
+
--filter '{"task":{"IN":[<taskIds>]},"status":{"IN":[1,3]},"date":{">=":<start>,"<=":<end>}}' \
|
|
223
|
+
--limit 10000 --json
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
3. If the user asks for all ticket time in a period, list actionsteps in the window with `ticket` and `task`, then resolve every referenced task to `task.ticket` and group by the resulting ticket ID. Page through results if the window is large.
|
|
227
|
+
4. Build each actionstep's ticket attribution:
|
|
228
|
+
- direct row: `actionstep.ticket`
|
|
229
|
+
- task row: `taskById[actionstep.task].ticket`
|
|
230
|
+
- both present: count the actionstep once; prefer the direct ticket if it conflicts and call out the conflict
|
|
231
|
+
- neither present: keep it out of the ticket-time total unless reporting an "unassigned/general time" bucket
|
|
232
|
+
5. Dedupe by actionstep `ID`, sum `effort` in minutes, and resolve ticket labels (`ticketnum`, `name`, `account.lastname`) for the summary.
|
|
233
|
+
|
|
234
|
+
Client shape for a specific ticket:
|
|
235
|
+
|
|
236
|
+
```js
|
|
237
|
+
const [directRows, taskRows] = await Promise.all([
|
|
238
|
+
client.api.listActionSteps({
|
|
239
|
+
fields: ['ID', 'name', 'effort', 'date', 'status', 'ticket', 'task', 'assigneduser'],
|
|
240
|
+
filters: { ticket: ticketId, status: { IN: [1, 3] }, date: { '>=': start, '<=': end } },
|
|
241
|
+
limit: 10000,
|
|
242
|
+
}),
|
|
243
|
+
client.api.listTasks({
|
|
244
|
+
fields: ['ID', 'tasknum', 'name', 'ticket'],
|
|
245
|
+
filters: { ticket: ticketId },
|
|
246
|
+
limit: 10000,
|
|
247
|
+
}),
|
|
248
|
+
]);
|
|
249
|
+
|
|
250
|
+
const taskIds = taskRows.map((task) => task.ID);
|
|
251
|
+
const taskTimeRows = taskIds.length
|
|
252
|
+
? await client.api.listActionSteps({
|
|
253
|
+
fields: ['ID', 'name', 'effort', 'date', 'status', 'ticket', 'task', 'assigneduser'],
|
|
254
|
+
filters: { task: { IN: taskIds }, status: { IN: [1, 3] }, date: { '>=': start, '<=': end } },
|
|
255
|
+
limit: 10000,
|
|
256
|
+
})
|
|
257
|
+
: [];
|
|
258
|
+
|
|
259
|
+
const rowsById = new Map();
|
|
260
|
+
for (const row of [...directRows, ...taskTimeRows]) rowsById.set(String(row.ID), row);
|
|
261
|
+
const totalMinutes = [...rowsById.values()]
|
|
262
|
+
.reduce((sum, row) => sum + (Number(row.effort) || 0), 0);
|
|
263
|
+
```
|
|
264
|
+
|
|
198
265
|
## Pattern: Adjust or correct a logged entry
|
|
199
266
|
|
|
200
267
|
For "actually that was 90 minutes, not 60" or "move that time to ticket 813" right after logging — or any later correction.
|
|
@@ -226,5 +293,6 @@ Only correct entries the user pointed to (by id, or one you just created in this
|
|
|
226
293
|
- Filtering `visibility` on `transactions` (no such column -> HTTP 400).
|
|
227
294
|
- Putting effort in hours — `effort` is **minutes**.
|
|
228
295
|
- Trying to set a `project` FK on an actionstep — it does not exist; anchor on a ticket/task/account instead.
|
|
296
|
+
- Summing only `actionstep.ticket` for ticket time — time logged on tasks with `task.ticket = <ticketId>` belongs in the ticket total too.
|
|
229
297
|
- Treating BOOKED (status 11) tickets as current — they are terminal; the open set excludes `[8,9,10,11]`.
|
|
230
298
|
- Logging time against a user id you guessed — always read `sub` from `whoami`.
|
|
@@ -30,9 +30,10 @@ Typical prompts:
|
|
|
30
30
|
4. Follow relationships only after the primary record set is clear.
|
|
31
31
|
5. Treat "worked on" as a proxy unless actionstep effort/date evidence exists. Assignment and timestamps show involvement; `actionsteps.effort` on `COMPLETED` or `BOOKED` records is stronger time-entry evidence.
|
|
32
32
|
6. Distinguish direct project assignment from project inference through linked tickets.
|
|
33
|
-
7.
|
|
34
|
-
8.
|
|
35
|
-
9.
|
|
33
|
+
7. For logged ticket-time summaries, include actionsteps directly linked to the ticket and actionsteps linked to tasks whose `task.ticket` is that ticket; dedupe actionstep IDs before summing.
|
|
34
|
+
8. When the question is really about account or transaction follow-up, check `actionsteps` before inventing a new task.
|
|
35
|
+
9. For mutations, preview the affected record first and update with an explicit PATCH body.
|
|
36
|
+
10. Escalate from the CLI to `@zeyos/client` if the workflow needs unsupported joins, additional request control, or correlation across multiple list responses.
|
|
36
37
|
|
|
37
38
|
## Destructive Operations
|
|
38
39
|
|
|
@@ -160,6 +160,7 @@ zeyos count actionsteps --filter '{"ticket":812,"status":0}' --json
|
|
|
160
160
|
Use this for prompts like:
|
|
161
161
|
|
|
162
162
|
- "How many minutes were booked on ticket 812 last week?"
|
|
163
|
+
- "Give me a summary of logged ticket time from the last four weeks."
|
|
163
164
|
- "Summarize completed actionstep effort for this account."
|
|
164
165
|
- "Which user logged effort against this project?"
|
|
165
166
|
|
|
@@ -169,7 +170,44 @@ Recommended approach:
|
|
|
169
170
|
2. Query `actionsteps` with fields `ID`, `date`, `status`, `effort`, and the relevant FK (`ticket`, `task`, `account`, or `transaction`).
|
|
170
171
|
3. Include statuses `1` COMPLETED and `3` BOOKED for time-entry totals unless the user asks for drafts/open follow-ups.
|
|
171
172
|
4. Sum `effort` as minutes; convert to hours only if the user asked for hours.
|
|
172
|
-
5.
|
|
173
|
+
5. For ticket-level totals, roll task time up to the ticket:
|
|
174
|
+
- direct ticket time is `actionsteps.ticket = <ticketId>`
|
|
175
|
+
- task ticket time is `actionsteps.task = <taskId>` where `tasks.ticket = <ticketId>`
|
|
176
|
+
- fetch tasks by `ticket` for a named ticket, or resolve every referenced `actionstep.task` to `task.ticket` for a period-wide ticket summary
|
|
177
|
+
- do not filter tasks by status when resolving historical time; a completed task can still carry valid logged time
|
|
178
|
+
- dedupe by `actionsteps.ID` before summing in case a row has both `ticket` and `task`
|
|
179
|
+
6. Keep task/ticket assignment separate from effort totals.
|
|
180
|
+
|
|
181
|
+
Ticket-specific client example:
|
|
182
|
+
|
|
183
|
+
```js
|
|
184
|
+
const [directRows, tasks] = await Promise.all([
|
|
185
|
+
client.api.listActionSteps({
|
|
186
|
+
fields: ['ID', 'date', 'status', 'effort', 'ticket', 'task', 'assigneduser'],
|
|
187
|
+
filters: { ticket: ticketId, status: { IN: [1, 3] }, date: { '>=': start, '<=': end } },
|
|
188
|
+
limit: 10000,
|
|
189
|
+
}),
|
|
190
|
+
client.api.listTasks({
|
|
191
|
+
fields: ['ID', 'ticket', 'name'],
|
|
192
|
+
filters: { ticket: ticketId },
|
|
193
|
+
limit: 10000,
|
|
194
|
+
}),
|
|
195
|
+
]);
|
|
196
|
+
|
|
197
|
+
const taskIds = tasks.map((task) => task.ID);
|
|
198
|
+
const taskRows = taskIds.length
|
|
199
|
+
? await client.api.listActionSteps({
|
|
200
|
+
fields: ['ID', 'date', 'status', 'effort', 'ticket', 'task', 'assigneduser'],
|
|
201
|
+
filters: { task: { IN: taskIds }, status: { IN: [1, 3] }, date: { '>=': start, '<=': end } },
|
|
202
|
+
limit: 10000,
|
|
203
|
+
})
|
|
204
|
+
: [];
|
|
205
|
+
|
|
206
|
+
const uniqueRows = new Map();
|
|
207
|
+
for (const row of [...directRows, ...taskRows]) uniqueRows.set(String(row.ID), row);
|
|
208
|
+
const totalMinutes = [...uniqueRows.values()]
|
|
209
|
+
.reduce((sum, row) => sum + (Number(row.effort) || 0), 0);
|
|
210
|
+
```
|
|
173
211
|
|
|
174
212
|
## Pattern: Create Follow-Up Work
|
|
175
213
|
|
|
@@ -78,7 +78,7 @@ zeyos logout [--global]
|
|
|
78
78
|
**Examples:**
|
|
79
79
|
|
|
80
80
|
```bash
|
|
81
|
-
zeyos logout # Clear local .zeyos/auth.json
|
|
81
|
+
zeyos logout # Clear local .zeyos/auth.json credentials
|
|
82
82
|
zeyos logout --global # Clear ~/.config/zeyos/credentials.json tokens
|
|
83
83
|
```
|
|
84
84
|
|
|
@@ -100,6 +100,11 @@ zeyos whoami --json
|
|
|
100
100
|
zeyos whoami --show-token --json # explicitly include the current access token
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
+
If the stored refresh token is invalid or expired, interactive text-mode `whoami`
|
|
104
|
+
prints the credential source and asks whether to re-authenticate immediately. In
|
|
105
|
+
`--json`, `--yaml`, or non-interactive runs, it exits with the same diagnostic and
|
|
106
|
+
prints the matching `zeyos login --force` command instead of prompting.
|
|
107
|
+
|
|
103
108
|
---
|
|
104
109
|
|
|
105
110
|
## profile
|
|
@@ -116,12 +121,13 @@ zeyos profile <list|current|use|add|remove> [options]
|
|
|
116
121
|
| `profile current` | Show which profile resolves right now, and why (flag/env/pin/active) |
|
|
117
122
|
| `profile use <name>` | Make `<name>` the active profile (global) |
|
|
118
123
|
| `profile use <name> --local` | Pin `<name>` to the current project (`.zeyos/profile`) |
|
|
119
|
-
| `profile add <name> [opts]` | Create/update a profile
|
|
124
|
+
| `profile add [<name>] [opts]` | Create/update a profile; prompts for missing values when run without options |
|
|
120
125
|
| `profile remove <name>` | Delete a profile |
|
|
121
126
|
|
|
122
127
|
**Examples:**
|
|
123
128
|
|
|
124
129
|
```bash
|
|
130
|
+
zeyos profile add # prompt for name, URL, app ID, secret
|
|
125
131
|
zeyos profile add dev --base-url https://zeyos.cms-it.de/dev
|
|
126
132
|
zeyos profile add prod --from-current # snapshot current credentials
|
|
127
133
|
zeyos login --profile prod # authenticate into & activate a profile
|
|
@@ -481,6 +487,34 @@ Skills are copied into `<dir>/<name>/`, with the shared reference files installe
|
|
|
481
487
|
|
|
482
488
|
---
|
|
483
489
|
|
|
490
|
+
## okf
|
|
491
|
+
|
|
492
|
+
Work with the [Open Knowledge Format](../06-okf/01-overview.md) bundle that ships with the
|
|
493
|
+
client — a portable Markdown description of the ZeyOS data model (one concept per
|
|
494
|
+
API-backed entity) plus curated metrics, playbooks, and query concepts.
|
|
495
|
+
|
|
496
|
+
```bash
|
|
497
|
+
zeyos okf list # list concepts (type, id, title); --json for automation
|
|
498
|
+
zeyos okf show tickets # print a concept (bare resource name, or entities/tickets)
|
|
499
|
+
zeyos okf check # validate OKF v0.1 conformance (exit non-zero on error)
|
|
500
|
+
zeyos okf export --out ./okf # copy the shipped bundle into a directory
|
|
501
|
+
zeyos okf build --out ./okf # synthesize a bundle from the client's schema
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
| Subcommand | What it does |
|
|
505
|
+
|-----------|--------------|
|
|
506
|
+
| `list` | List the concepts in the bundle (`--json`/`--yaml` supported). |
|
|
507
|
+
| `show <concept>` | Print one concept doc. Accepts a bare resource (`tickets`) or full id (`entities/tickets`). |
|
|
508
|
+
| `check` | Validate the bundle for OKF v0.1 conformance; exits non-zero on any error (CI-friendly). |
|
|
509
|
+
| `export` | Copy the shipped `okf/` bundle into `--out` (default `./okf`); `--force` to overwrite. |
|
|
510
|
+
| `build` | Synthesize a structural bundle from the client's schema into `--out` (default `./okf`). |
|
|
511
|
+
|
|
512
|
+
Options: `--dir <path>` reads from an explicit bundle directory (`list`/`show`/`check`);
|
|
513
|
+
`--out <path>` is the write target (`build`/`export`); `--force` overwrites an existing
|
|
514
|
+
target. `export` ships the rich curated bundle; `build` is the lighter runtime projection.
|
|
515
|
+
|
|
516
|
+
---
|
|
517
|
+
|
|
484
518
|
## Command Aliases
|
|
485
519
|
|
|
486
520
|
| Alias | Equivalent |
|
|
@@ -33,6 +33,7 @@ Profiles let you store several ZeyOS instances (e.g. `dev`, `prod`, `client-x`)
|
|
|
33
33
|
|
|
34
34
|
```bash
|
|
35
35
|
# Create profiles (connection params now; tokens via login)
|
|
36
|
+
zeyos profile add # interactive wizard
|
|
36
37
|
zeyos profile add dev --base-url https://zeyos.cms-it.de/dev
|
|
37
38
|
zeyos profile add prod --base-url https://cloud.zeyos.com/acme --client-id app --secret "$SECRET"
|
|
38
39
|
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# OKF Overview
|
|
2
|
+
|
|
3
|
+
The **Open Knowledge Format (OKF v0.1)** is Google's minimal, vendor-neutral spec for
|
|
4
|
+
sharing the metadata and curated context that surrounds data: a directory of Markdown
|
|
5
|
+
files, each with YAML frontmatter whose only required field is `type`, optional `index.md`
|
|
6
|
+
and `log.md`, and Markdown cross-links that turn the directory into a knowledge graph.
|
|
7
|
+
Producers emit a bundle; consumers (coding agents, viewers, search) read it.
|
|
8
|
+
|
|
9
|
+
`@zeyos/client` ships a conformant OKF bundle under [`okf/`](https://github.com/zeyos/client/tree/main/okf)
|
|
10
|
+
that describes the ZeyOS data model, and tooling to produce, consume, validate, and refine it.
|
|
11
|
+
|
|
12
|
+
## Why OKF fits ZeyOS
|
|
13
|
+
|
|
14
|
+
The client already derives a compact schema from the OpenAPI/dbref specs. OKF turns that —
|
|
15
|
+
plus the curated business knowledge that used to live only in the skill pack — into a
|
|
16
|
+
portable knowledge layer any agent or tool can read, independent of this client.
|
|
17
|
+
|
|
18
|
+
The bundle is **canonical** for ZeyOS structural facts: the hand-maintained
|
|
19
|
+
`agents/shared/zeyos-entity-reference.md` operationId table is now generated from the same
|
|
20
|
+
source, so the skills and the OKF bundle can't drift apart.
|
|
21
|
+
|
|
22
|
+
## Bundle layout
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
okf/
|
|
26
|
+
index.md # root listing; frontmatter: okf_version, source_snapshot
|
|
27
|
+
log.md # schema-change history (auto-appended on real changes)
|
|
28
|
+
entities/ # one concept per API-backed entity — type: ZeyOS Entity
|
|
29
|
+
index.md
|
|
30
|
+
accounts.md tickets.md transactions.md …
|
|
31
|
+
metrics/ # business metric definitions — type: Metric
|
|
32
|
+
playbooks/ # step-by-step query workflows — type: Playbook
|
|
33
|
+
concepts/ # cross-cutting rules / footguns — type: Reference
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Each entity concept carries a **Schema** table (column, type, nullability, default, index,
|
|
37
|
+
foreign key), **Foreign Keys** (cross-linked to the target entity), **Enums** (parsed from
|
|
38
|
+
the schema), **Indexes** (including the GIN/partial indexes behind the `filters` footgun),
|
|
39
|
+
and **Operations** (the real `@zeyos/client` operationIds, read straight from `api.json`).
|
|
40
|
+
|
|
41
|
+
## Generated vs curated: managed blocks
|
|
42
|
+
|
|
43
|
+
Each entity concept mixes auto-generated structure with curated prose. The generated region
|
|
44
|
+
is fenced by HTML-comment markers:
|
|
45
|
+
|
|
46
|
+
```markdown
|
|
47
|
+
<!-- okf:generated:start — rewritten by scripts/generate-okf.mjs; do not edit by hand -->
|
|
48
|
+
# Schema
|
|
49
|
+
…
|
|
50
|
+
<!-- okf:generated:end -->
|
|
51
|
+
|
|
52
|
+
# Notes
|
|
53
|
+
Curated guidance — preserved across every regeneration.
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The producer rewrites **only** the region between the markers. Curated `# Notes`/`# Metrics`
|
|
57
|
+
prose (added by a human or the refinement loop) is preserved verbatim, so regenerating after
|
|
58
|
+
a schema change never clobbers curation. See [Keeping OKF fresh](./03-keeping-fresh.md).
|
|
59
|
+
|
|
60
|
+
## Relationship to the skill pack
|
|
61
|
+
|
|
62
|
+
Two projections of one knowledge core:
|
|
63
|
+
|
|
64
|
+
- **Skills** (`agents/`) stay the task/runner-facing layer: the operating contract, "act,
|
|
65
|
+
don't plan", and safety.
|
|
66
|
+
- **OKF** (`okf/`) is the reference layer: the entity schema-of-record plus the metric,
|
|
67
|
+
playbook, and concept catalog.
|
|
68
|
+
|
|
69
|
+
Skills point into `okf/`; when a schema fact in a shared reference and in `okf/` ever
|
|
70
|
+
disagree, `okf/` wins.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Producing & Consuming OKF
|
|
2
|
+
|
|
3
|
+
## CLI
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
zeyos okf list # list concepts (type, id, title); --json for automation
|
|
7
|
+
zeyos okf show tickets # print a concept (bare resource name or entities/tickets)
|
|
8
|
+
zeyos okf check # validate the bundle for OKF v0.1 conformance (exit non-zero on error)
|
|
9
|
+
zeyos okf export --out ./okf # copy the shipped bundle into a directory
|
|
10
|
+
zeyos okf build --out ./okf # synthesize a bundle from the client's schema
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`export` copies the rich shipped bundle (with curated metrics/playbooks/notes). `build`
|
|
14
|
+
synthesizes a structural bundle from the client's introspection surface — useful where the
|
|
15
|
+
shipped files aren't present, or to diff against a live instance.
|
|
16
|
+
|
|
17
|
+
## JavaScript client
|
|
18
|
+
|
|
19
|
+
The OKF surface is exported from `@zeyos/client`:
|
|
20
|
+
|
|
21
|
+
```js
|
|
22
|
+
import { buildOkf, loadOkfBundle, validateOkfBundle, validateOkfFiles, OKF_VERSION } from '@zeyos/client';
|
|
23
|
+
|
|
24
|
+
// Synthesize a conformant bundle from the client's generated schema (pure; browser-safe).
|
|
25
|
+
const files = buildOkf(); // { 'entities/tickets.md': '…', … }
|
|
26
|
+
const { valid, errors } = validateOkfFiles(files);
|
|
27
|
+
|
|
28
|
+
// Load the shipped (or any) bundle from disk (Node only).
|
|
29
|
+
const bundle = await loadOkfBundle('node_modules/@zeyos/client/okf');
|
|
30
|
+
bundle.version; // '0.1'
|
|
31
|
+
bundle.concepts['entities/tickets'].frontmatter // { type: 'ZeyOS Entity', title: 'Tickets', … }
|
|
32
|
+
|
|
33
|
+
// Validate a directory or an in-memory file map.
|
|
34
|
+
await validateOkfBundle('okf');
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
- `buildOkf({ schema?, services? })` — pure producer; defaults to the generated `SCHEMA`/`SERVICES`.
|
|
38
|
+
- `loadOkfBundle(dir)` — Node-only reader (lazy `fs`), returns `{ version, files, concepts }`.
|
|
39
|
+
- `validateOkfBundle(dirOrFiles)` / `validateOkfFiles(files)` — v0.1 conformance check.
|
|
40
|
+
|
|
41
|
+
## Build-time producer
|
|
42
|
+
|
|
43
|
+
In this repo, `npm run okf:build` (or `npm run generate`, which runs it alongside the client
|
|
44
|
+
codegen) emits the rich bundle from `openapi/{api,dbref}.json` plus the curated content in
|
|
45
|
+
`scripts/data/okf-curation.mjs`. It also injects the generated operationId table into
|
|
46
|
+
`agents/shared/zeyos-entity-reference.md`. Validate with `npm run okf:check`.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Keeping OKF Fresh
|
|
2
|
+
|
|
3
|
+
The OKF bundle is generated from the OpenAPI/dbref snapshots in `openapi/`. When ZeyOS
|
|
4
|
+
updates its database model or API, those specs are re-exported and the bundle is
|
|
5
|
+
regenerated. The design keeps that safe and observable.
|
|
6
|
+
|
|
7
|
+
## What protects curation
|
|
8
|
+
|
|
9
|
+
1. **Deterministic generation.** `npm run generate` runs the OKF producer alongside the
|
|
10
|
+
client codegen. Re-running with unchanged specs produces **no diff** (no timestamp churn).
|
|
11
|
+
2. **Managed blocks.** Only the fenced `okf:generated` region of each entity concept is
|
|
12
|
+
rewritten; curated `# Notes`/`# Metrics` prose is spliced back unchanged. See the
|
|
13
|
+
[overview](./01-overview.md#generated-vs-curated-managed-blocks).
|
|
14
|
+
3. **`source_snapshot`.** The root `index.md` frontmatter carries a content hash of the
|
|
15
|
+
schema. When the specs change, the hash changes — a staleness signal for consumers and
|
|
16
|
+
the drift gate.
|
|
17
|
+
4. **`log.md` schema diff.** The producer diffs the new schema against the last snapshot and
|
|
18
|
+
appends a dated entry (added/removed fields, changed enums, new foreign keys) — an
|
|
19
|
+
OKF-native, human- and agent-readable record of *what changed when the model updated*.
|
|
20
|
+
|
|
21
|
+
## The spec-refresh runbook
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# 1. Replace the snapshots with the newly exported specs
|
|
25
|
+
# openapi/api.json, openapi/dbref.json
|
|
26
|
+
|
|
27
|
+
# 2. Regenerate the client and the OKF bundle
|
|
28
|
+
npm run generate
|
|
29
|
+
|
|
30
|
+
# 3. Review the diff and the changelog
|
|
31
|
+
git diff okf/ agents/shared/zeyos-entity-reference.md
|
|
32
|
+
cat okf/log.md # newest dated entry summarizes the schema changes
|
|
33
|
+
|
|
34
|
+
# 4. Validate conformance + the drift gate
|
|
35
|
+
npm run okf:check
|
|
36
|
+
|
|
37
|
+
# 5. (Optional) enrich weak concepts — see ./04-loops.md
|
|
38
|
+
npm run okf:refine -- --concept entities/<changed-entity>
|
|
39
|
+
|
|
40
|
+
# 6. Commit
|
|
41
|
+
git add okf agents/shared src/generated && git commit -m "Refresh schema + OKF"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## The drift gate (CI)
|
|
45
|
+
|
|
46
|
+
`npm run okf:check` runs `test/okf.test.js`, which regenerates the bundle and asserts the
|
|
47
|
+
committed content matches a fresh regen. It fails the build when:
|
|
48
|
+
|
|
49
|
+
- the specs changed but `okf/` wasn't regenerated and committed;
|
|
50
|
+
- someone hand-edited a generated region;
|
|
51
|
+
- a concept is non-conformant, an API-backed entity lacks a concept, or a structural
|
|
52
|
+
cross-link is broken;
|
|
53
|
+
- the shared reference's generated operationId table fell out of sync.
|