@zeyos/client 0.1.1 → 0.3.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 +35 -0
- package/agents/README.md +18 -6
- package/agents/shared/zeyos-agent-operating-guide.md +112 -0
- package/agents/shared/zeyos-query-patterns.md +12 -1
- package/agents/zeyos/SKILL.md +95 -0
- package/agents/zeyos-account-intelligence/SKILL.md +1 -1
- package/agents/zeyos-account-intelligence/references/workflows.md +7 -0
- package/agents/zeyos-billing-insights/SKILL.md +6 -1
- package/agents/zeyos-billing-insights/references/workflows.md +32 -3
- package/agents/zeyos-campaign-and-outreach/SKILL.md +1 -1
- package/agents/zeyos-campaign-and-outreach/references/workflows.md +8 -0
- package/agents/zeyos-collaboration-and-activity/SKILL.md +1 -1
- package/agents/zeyos-collaboration-and-activity/references/workflows.md +9 -0
- package/agents/zeyos-collections-and-dunning/SKILL.md +1 -1
- package/agents/zeyos-commerce-and-inventory/SKILL.md +1 -1
- package/agents/zeyos-commerce-and-inventory/references/workflows.md +7 -0
- package/agents/zeyos-mail-operations/SKILL.md +8 -2
- package/agents/zeyos-mail-operations/references/workflows.md +19 -2
- package/agents/zeyos-notes-and-sops/SKILL.md +1 -1
- package/agents/zeyos-platform-and-schema/SKILL.md +2 -2
- package/agents/zeyos-platform-and-schema/references/workflows.md +24 -0
- package/agents/zeyos-time-tracking/SKILL.md +48 -0
- package/agents/zeyos-time-tracking/references/workflows.md +230 -0
- package/agents/zeyos-work-management/SKILL.md +6 -3
- package/agents/zeyos-work-management/references/workflows.md +54 -4
- package/docs/02-javascript-client/03-making-requests.md +46 -1
- package/docs/03-cli/01-getting-started.md +7 -0
- package/docs/03-cli/02-commands.md +63 -1
- package/docs/03-cli/03-configuration.md +37 -5
- package/docs/04-agent-workflows/01-agent-quickstart.md +24 -0
- package/docs/04-agent-workflows/03-cli-coverage-and-escalation.md +3 -2
- package/package.json +6 -3
- package/src/runtime/client.js +226 -18
|
@@ -5,7 +5,7 @@ description: Inspect ZeyOS platform, schema, and admin-facing entities such as a
|
|
|
5
5
|
|
|
6
6
|
# ZeyOS Platform And Schema
|
|
7
7
|
|
|
8
|
-
Read [../shared/zeyos-query-patterns.md](../shared/zeyos-query-patterns.md) first. Read [../shared/zeyos-entity-reference.md](../shared/zeyos-entity-reference.md) for the full source-backed model. Read [references/workflows.md](references/workflows.md) for platform/admin query plans.
|
|
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. Read [../shared/zeyos-entity-reference.md](../shared/zeyos-entity-reference.md) for the full source-backed model. Read [references/workflows.md](references/workflows.md) for platform/admin query plans.
|
|
9
9
|
|
|
10
10
|
Typical prompts:
|
|
11
11
|
|
|
@@ -26,7 +26,7 @@ Typical prompts:
|
|
|
26
26
|
3. Use:
|
|
27
27
|
- `applications`, `resources`, `services`, `weblets`, `forks` for platform structure
|
|
28
28
|
- `groups`, `groups2users`, `permissions` for access control (`groups2users` -> `listGroupsToUsers` / `getGroupToUser`)
|
|
29
|
-
- `customfields`, `objects`, and extdata helper families for schema and custom data (`customfields`
|
|
29
|
+
- `customfields`, `objects`, and extdata helper families for schema and custom data (`customfields` is exposed in the CLI as `customfields` for read/count; in the JS client it maps to `listCustomFields`; `applicationassets` -> `listApplicationAssets`; these dbref nouns do not map naively — see [../shared/zeyos-entity-reference.md](../shared/zeyos-entity-reference.md#entity-noun-to-rest-operationid))
|
|
30
30
|
4. Treat `records`, `comments`, `files`, `channels`, `follows`, and `likes` as a collaboration layer. Switch to `zeyos-collaboration-and-activity` when the user asks for timeline or discussion behavior rather than platform structure.
|
|
31
31
|
5. Be explicit when the schema tells you structure but not the product convention.
|
|
32
32
|
|
|
@@ -22,6 +22,30 @@ These are dbref nouns, not operationIds. Several diverge: `applicationassets` ->
|
|
|
22
22
|
[../../shared/zeyos-entity-reference.md](../../shared/zeyos-entity-reference.md#entity-noun-to-rest-operationid)
|
|
23
23
|
before calling `@zeyos/client`.
|
|
24
24
|
|
|
25
|
+
## First Commands For Counts
|
|
26
|
+
|
|
27
|
+
- All custom fields: `zeyos count customfields --json`
|
|
28
|
+
- Custom fields for tickets: `zeyos count customfields --filter '{"entity":"tickets"}' --json`
|
|
29
|
+
|
|
30
|
+
`customfields` is read-only and has no `visibility` field. In the JS client the list
|
|
31
|
+
operation is `listCustomFields`, not `listCustomfields`.
|
|
32
|
+
|
|
33
|
+
For a total count, use the `count` value from the CLI JSON response. Do not answer `0`
|
|
34
|
+
because `customfields` is missing from an old CLI registry, because a command failed, or
|
|
35
|
+
because `zeyos resources` did not list it. If `zeyos count customfields` fails with
|
|
36
|
+
"Unknown resource", run `zeyos doctor agent --json` to inspect the CLI version and then
|
|
37
|
+
switch to the JavaScript client:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
node --input-type=module -e 'const { createZeyosClient, normalizeListResult } = await import(`${process.env.ZEYOS_REPO_ROOT}/src/index.js`);
|
|
41
|
+
const client = createZeyosClient({
|
|
42
|
+
platform: process.env.ZEYOS_BASE_URL,
|
|
43
|
+
auth: { mode: "oauth", oauth: { token: { accessToken: process.env.ZEYOS_TOKEN }, autoRefresh: false } }
|
|
44
|
+
});
|
|
45
|
+
const rows = normalizeListResult(await client.api.listCustomFields({ limit: 10000 })).data;
|
|
46
|
+
console.log(rows.length);'
|
|
47
|
+
```
|
|
48
|
+
|
|
25
49
|
## Pattern: Custom Fields For An Entity
|
|
26
50
|
|
|
27
51
|
Use this for prompts like:
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: zeyos-time-tracking
|
|
3
|
+
description: First-person personal work and interactive time logging in ZeyOS. Use when the user speaks about their own work ("what are my current tickets?", "what's on my plate?", "what am I working on?", "my open tasks", "my action steps") or wants to record/log/book time or effort ("log 60 minutes for client XYZ", "record 2 hours on ticket 812", "book time against Project Atlas"). Resolves the current user, finds the right account and the candidate ticket/task/project to attach time to, confirms the target with the user, then writes the time entry as an actionstep with `effort`.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# ZeyOS Time Tracking
|
|
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. Read [references/workflows.md](references/workflows.md) for the concrete query and write patterns. This skill overlaps with [../zeyos-work-management/SKILL.md](../zeyos-work-management/SKILL.md): use **work-management** for third-person, analytical queries about other people's queues, project tracing, and effort *summaries*; use **time-tracking** when the request is **first-person** ("my …") or is about **recording new time**.
|
|
9
|
+
|
|
10
|
+
Typical prompts:
|
|
11
|
+
|
|
12
|
+
- "What are my current tickets?" / "What's on my plate?" / "What am I working on?"
|
|
13
|
+
- "Show my open tasks." / "What action steps are assigned to me?"
|
|
14
|
+
- "Log 60 minutes of work for client XYZ."
|
|
15
|
+
- "Record 2 hours on ticket 812." / "Book 90 minutes against Project Atlas."
|
|
16
|
+
- "Log half an hour for ACME, I was on a call about the renewal."
|
|
17
|
+
- "How much time did I log this week?" / "Summarize my logged hours by account."
|
|
18
|
+
- "Actually make that 90 minutes, not 60." / "Move that time to ticket 813."
|
|
19
|
+
|
|
20
|
+
## Two jobs
|
|
21
|
+
|
|
22
|
+
1. **Read "my work"** — resolve the current user, then list their open tickets / tasks / action steps. Read-only; just run it.
|
|
23
|
+
2. **Log time (a write)** — resolve *who* the time is for, *what* it attaches to, then create one `actionstep` carrying the effort. This is interactive and confirmed.
|
|
24
|
+
|
|
25
|
+
## The current user
|
|
26
|
+
|
|
27
|
+
The logged-in user's id is `getUserInfo().sub` — a stringified positive integer that **is** the `users.ID`. Get it from `zeyos whoami --json` (read the `sub` field) before any "my …" query, and use it as `assigneduser` on the work resources. Do not guess it and do not ask the user for it.
|
|
28
|
+
|
|
29
|
+
## Interactive discipline (this is the point of the skill)
|
|
30
|
+
|
|
31
|
+
Interactivity here means **act first, then ask only when real data is ambiguous** — never the planning-instead-of-running failure the operating guide warns about.
|
|
32
|
+
|
|
33
|
+
1. **Always run the resolution queries before asking anything.** "I found 3 accounts matching 'XYZ' — which one?" is good (grounded in a query you ran). "Which account do you mean?" with no search behind it is not.
|
|
34
|
+
2. **Ask only when the data is genuinely ambiguous** and the answer changes the write: multiple account matches, or several plausible tickets/tasks. A single unambiguous match needs no question — state it and continue.
|
|
35
|
+
3. **Confirm the target before the write.** Time logging creates a record. The user's "log 60 minutes" authorizes *one* entry; the confirmation is about *where* it lands (which work item) and *what* it says — show the actionstep you are about to create and let the user correct it.
|
|
36
|
+
4. **Never invent the attachment.** If you cannot resolve a confident target and there is no human to ask (e.g. an automated run), stop and report what you found rather than guessing a foreign key for a write.
|
|
37
|
+
|
|
38
|
+
## Safety
|
|
39
|
+
|
|
40
|
+
- Read views are read-only; run them directly.
|
|
41
|
+
- Logging time is a **create**, allowed because the user explicitly asked to log it. Preview with `--query` and confirm the target first; create exactly one record; then read it back.
|
|
42
|
+
- Never delete or bulk-modify time entries on a category ("clear my logged time", "remove old entries") — those are per-record, by id, after preview. See the destructive-operations rules in [../zeyos-work-management/SKILL.md](../zeyos-work-management/SKILL.md).
|
|
43
|
+
|
|
44
|
+
## Output discipline
|
|
45
|
+
|
|
46
|
+
- For "my work": state the resolved user and the open-status definition you used, then the list.
|
|
47
|
+
- For a logged entry: report the created actionstep id, the attached record (ticket/task/account), the effort in minutes, and the date.
|
|
48
|
+
- Separate what you resolved from what you assumed; call out any account or work-item ambiguity you had to break.
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# Time Tracking Workflows
|
|
2
|
+
|
|
3
|
+
## Resources and operation IDs
|
|
4
|
+
|
|
5
|
+
These are dbref nouns; the REST/client operationIds differ for action steps (compound CamelCase):
|
|
6
|
+
|
|
7
|
+
- `tickets` -> `listTickets` / `getTicket` / `createTicket` / `updateTicket`
|
|
8
|
+
- `tasks` -> `listTasks` / `getTask` / `createTask` / `updateTask`
|
|
9
|
+
- `projects` -> `listProjects` / `getProject`
|
|
10
|
+
- `accounts` -> `listAccounts` / `getAccount`
|
|
11
|
+
- `actionsteps` -> `listActionSteps` / `getActionStep` / `createActionStep` / `updateActionStep` (not `listActionsteps`)
|
|
12
|
+
- current user -> `getUserInfo` (oauth2 service); `zeyos whoami --json` exposes its `sub`
|
|
13
|
+
|
|
14
|
+
See [../../shared/zeyos-entity-reference.md](../../shared/zeyos-entity-reference.md#entity-noun-to-rest-operationid) before calling `@zeyos/client`.
|
|
15
|
+
|
|
16
|
+
## Schema facts this skill relies on
|
|
17
|
+
|
|
18
|
+
- **Time entries are `actionsteps`.** The `effort` field is **minutes** (integer). There is no separate time-entry resource.
|
|
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
|
+
- **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
|
+
- **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
|
+
- **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).
|
|
23
|
+
- **Visibility:** `tickets`, `tasks`, `projects`, `accounts` expose `visibility` (use `0` for live records). `transactions` do **not** — never filter `visibility` there.
|
|
24
|
+
- All dates are **Unix timestamps in seconds**.
|
|
25
|
+
|
|
26
|
+
## Filter operators (server-side)
|
|
27
|
+
|
|
28
|
+
`{"field": value}` is equality. Object values take operators: `{">=":3}`, `{"!=":0}`, `{"IN":[1,3]}`, `{"!IN":[8,9,10,11]}`. For name search, `~~*` is case-insensitive LIKE: `{"lastname": {"~~*": "%acme%"}}`. The client accepts `filters` (plural); the CLI flag is `--filter` (it writes `filters` internally).
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Pattern: "What are my current tickets / tasks / action steps?"
|
|
33
|
+
|
|
34
|
+
1. Resolve the current user id:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
zeyos whoami --json # read the "sub" field — this is your users.ID
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
2. List open work assigned to that id. Use `--limit` high enough that nothing is silently truncated, or `zeyos count` first if the user asked "how many".
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# my open tickets, most urgent first
|
|
44
|
+
zeyos list tickets \
|
|
45
|
+
--fields ID,ticketnum,name,status,priority,duedate,account.lastname,project \
|
|
46
|
+
--filter '{"assigneduser":<sub>,"visibility":0,"status":{"!IN":[8,9,10,11]}}' \
|
|
47
|
+
--sort -priority,+duedate \
|
|
48
|
+
--limit 200 --json
|
|
49
|
+
|
|
50
|
+
# my open tasks
|
|
51
|
+
zeyos list tasks \
|
|
52
|
+
--fields ID,tasknum,name,status,priority,duedate,ticket,project,projectedeffort \
|
|
53
|
+
--filter '{"assigneduser":<sub>,"visibility":0,"status":{"!IN":[8,9,10,11]}}' \
|
|
54
|
+
--sort -priority,+duedate --limit 200 --json
|
|
55
|
+
|
|
56
|
+
# my open action steps (follow-ups)
|
|
57
|
+
zeyos list actionsteps \
|
|
58
|
+
--fields ID,actionnum,name,status,date,duedate,effort,ticket,task,account \
|
|
59
|
+
--filter '{"assigneduser":<sub>,"status":0}' \
|
|
60
|
+
--sort +duedate --limit 200 --json
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Client form:
|
|
64
|
+
|
|
65
|
+
```js
|
|
66
|
+
const me = await client.oauth2.getUserInfo(); // me.sub === users.ID (string)
|
|
67
|
+
const myTickets = await client.api.listTickets({
|
|
68
|
+
fields: ['ID', 'ticketnum', 'name', 'status', 'priority', 'duedate', 'account.lastname', 'project'],
|
|
69
|
+
filters: { assigneduser: me.sub, visibility: 0, status: { '!IN': [8, 9, 10, 11] } },
|
|
70
|
+
limit: 200,
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
3. Report the resolved user and the open-status definition, then the list ordered by priority and due date. Flag overdue items (`duedate < now`).
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Pattern: Interactive time logging — "Log 60 minutes of work for client XYZ"
|
|
79
|
+
|
|
80
|
+
This is the headline interactive flow. Run each step; ask the user only at the marked decision points.
|
|
81
|
+
|
|
82
|
+
### Step 1 — Parse the request
|
|
83
|
+
|
|
84
|
+
- **Duration -> minutes.** "60 minutes" -> `60`; "2 hours" -> `120`; "1.5h"/"an hour and a half" -> `90`; "half an hour" -> `30`. `effort` is integer minutes.
|
|
85
|
+
- **Date.** Default to now (`date` = current Unix seconds). Honor an explicit date if given ("yesterday", "on Monday").
|
|
86
|
+
- **Note.** Use any description the user gave ("call about the renewal") as the actionstep `name`/`description`; otherwise compose a short one and confirm it.
|
|
87
|
+
|
|
88
|
+
### Step 2 — Resolve the account (ask only if ambiguous)
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
zeyos list accounts \
|
|
92
|
+
--fields ID,customernum,lastname,firstname,type \
|
|
93
|
+
--filter '{"visibility":0,"lastname":{"~~*":"%xyz%"}}' \
|
|
94
|
+
--limit 25 --json
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
- Also try `customernum` and `firstname` if `lastname` yields nothing.
|
|
98
|
+
- **0 matches:** report it and ask for a customer number or exact name — do not create anything.
|
|
99
|
+
- **1 match:** state it ("Logging against ACME Corp (#10042)") and continue.
|
|
100
|
+
- **>1 match (DECISION POINT):** list the candidates with `customernum`, name, and `type`, and ask which one. Do not guess.
|
|
101
|
+
|
|
102
|
+
### Step 3 — Enumerate candidate work items for that account
|
|
103
|
+
|
|
104
|
+
Run these in parallel; you are building the menu of places the time could land. (Tasks have no `account` FK, so reach them through the account's tickets/projects.)
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# open tickets on the account
|
|
108
|
+
zeyos list tickets --fields ID,ticketnum,name,status,priority \
|
|
109
|
+
--filter '{"account":<accountId>,"visibility":0,"status":{"!IN":[8,9,10,11]}}' --limit 50 --json
|
|
110
|
+
|
|
111
|
+
# active projects on the account
|
|
112
|
+
zeyos list projects --fields ID,projectnum,name,status \
|
|
113
|
+
--filter '{"account":<accountId>,"visibility":0,"status":{"!IN":[8,9,10,11]}}' --limit 50 --json
|
|
114
|
+
|
|
115
|
+
# open tasks under those tickets/projects (use the IDs gathered above)
|
|
116
|
+
zeyos list tasks --fields ID,tasknum,name,status,ticket,project \
|
|
117
|
+
--filter '{"visibility":0,"status":{"!IN":[8,9,10,11]},"ticket":{"IN":[<ticketIds>]}}' --limit 50 --json
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Step 4 — Choose the attachment (DECISION POINT)
|
|
121
|
+
|
|
122
|
+
Present the candidates grouped (tickets / tasks / projects) and ask where the time should go. Map the choice to exactly one actionstep FK:
|
|
123
|
+
|
|
124
|
+
- a ticket -> `ticket: <id>`
|
|
125
|
+
- a task -> `task: <id>`
|
|
126
|
+
- a project -> attach to a ticket/task in that project, or fall back to the project's `account` (no `project` FK exists on actionsteps — say so)
|
|
127
|
+
- "just the account / general" or no work items exist -> `account: <accountId>`
|
|
128
|
+
|
|
129
|
+
If there is exactly one obvious candidate (e.g. a single open ticket), propose it as the default and let the user confirm rather than asking open-endedly.
|
|
130
|
+
|
|
131
|
+
### Step 5 — Preview, confirm, then write
|
|
132
|
+
|
|
133
|
+
Preview the exact request without sending it, show it to the user, and create it only after confirmation:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
# dry-run preview (no network, no write)
|
|
137
|
+
zeyos create actionstep \
|
|
138
|
+
--name "Call about the renewal" \
|
|
139
|
+
--ticket <ticketId> \
|
|
140
|
+
--account <accountId> \
|
|
141
|
+
--assigneduser <sub> \
|
|
142
|
+
--effort 60 --status 1 --date <nowSeconds> \
|
|
143
|
+
--query
|
|
144
|
+
|
|
145
|
+
# after the user confirms, drop --query to actually create, then read it back
|
|
146
|
+
zeyos create actionstep --name "Call about the renewal" --ticket <ticketId> \
|
|
147
|
+
--assigneduser <sub> --effort 60 --status 1 --date <nowSeconds> --json
|
|
148
|
+
zeyos get actionstep <newId> --json
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Client form:
|
|
152
|
+
|
|
153
|
+
```js
|
|
154
|
+
const now = Math.floor(Date.now() / 1000);
|
|
155
|
+
const created = await client.api.createActionStep({
|
|
156
|
+
name: 'Call about the renewal',
|
|
157
|
+
ticket: ticketId, // or task / account — exactly one work anchor
|
|
158
|
+
assigneduser: me.sub,
|
|
159
|
+
effort: 60, // minutes
|
|
160
|
+
status: 1, // COMPLETED (logged work)
|
|
161
|
+
date: now,
|
|
162
|
+
});
|
|
163
|
+
const verify = await client.api.getActionStep({ ID: created.ID });
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Set **one** of `ticket` / `task` / `account` as the work anchor (a ticket already implies its account, so you do not need both). Report the created id, the anchor, effort minutes, and date.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Pattern: "How much time did I log this week?" (timesheet summary)
|
|
171
|
+
|
|
172
|
+
The read complement to logging — totals the effort the current user already booked over a period, optionally grouped by account/ticket.
|
|
173
|
+
|
|
174
|
+
1. Resolve the current user id (`zeyos whoami --json` → `sub`).
|
|
175
|
+
2. Normalize the window to Unix **seconds**. The actionstep `date` field carries the business date of the entry; filter on it.
|
|
176
|
+
3. List the user's time entries in the window and sum `effort` (minutes). Count only COMPLETED (1) and BOOKED (3) — those are real logged time, not open follow-ups (status 0).
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
# my logged minutes between two timestamps
|
|
180
|
+
zeyos list actionsteps \
|
|
181
|
+
--fields ID,name,effort,date,status,account,ticket,task \
|
|
182
|
+
--filter '{"assigneduser":<sub>,"status":{"IN":[1,3]},"date":{">=":<weekStart>,"<=":<weekEnd>}}' \
|
|
183
|
+
--limit 10000 --json
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
```js
|
|
187
|
+
const me = await client.oauth2.getUserInfo();
|
|
188
|
+
const rows = await client.api.listActionSteps({
|
|
189
|
+
fields: ['ID', 'effort', 'date', 'status', 'account', 'ticket', 'task'],
|
|
190
|
+
filters: { assigneduser: me.sub, status: { IN: [1, 3] }, date: { '>=': weekStart, '<=': weekEnd } },
|
|
191
|
+
limit: 10000,
|
|
192
|
+
});
|
|
193
|
+
const totalMinutes = rows.reduce((sum, r) => sum + (Number(r.effort) || 0), 0);
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
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
|
+
## Pattern: Adjust or correct a logged entry
|
|
199
|
+
|
|
200
|
+
For "actually that was 90 minutes, not 60" or "move that time to ticket 813" right after logging — or any later correction.
|
|
201
|
+
|
|
202
|
+
1. Get the entry first so you preview the current values: `zeyos get actionstep <id> --json`.
|
|
203
|
+
2. Build a minimal PATCH with only the changed fields. Preview with `--query`, confirm with the user (it is a mutation on an existing record), then update and read back.
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
zeyos update actionstep <id> --effort 90 --query # preview the change
|
|
207
|
+
zeyos update actionstep <id> --effort 90 --json # after confirmation
|
|
208
|
+
zeyos get actionstep <id> --json # verify
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
```js
|
|
212
|
+
await client.api.updateActionStep({ ID: id, effort: 90 }); // spread form: ID + changed fields
|
|
213
|
+
const verify = await client.api.getActionStep({ ID: id });
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Only correct entries the user pointed to (by id, or one you just created in this turn). Re-anchoring time to a different work item means changing the `ticket`/`task`/`account` FK — set the new anchor and clear the old one if it conflicts. Never bulk-rewrite a category of entries.
|
|
217
|
+
|
|
218
|
+
## Degrading when there is no human (automated / harness runs)
|
|
219
|
+
|
|
220
|
+
- "My work" reads still work: resolve `sub`, run the list, report it.
|
|
221
|
+
- For a **write**, never break ambiguity by guessing. If the account or the work item is ambiguous and nothing can be asked, stop and report the candidates and what was missing. A wrong foreign key on a created time entry is worse than an unanswered request.
|
|
222
|
+
|
|
223
|
+
## Common failure modes
|
|
224
|
+
|
|
225
|
+
- Counting a `list` page instead of the real total — use `zeyos count` for "how many of my …".
|
|
226
|
+
- Filtering `visibility` on `transactions` (no such column -> HTTP 400).
|
|
227
|
+
- Putting effort in hours — `effort` is **minutes**.
|
|
228
|
+
- Trying to set a `project` FK on an actionstep — it does not exist; anchor on a ticket/task/account instead.
|
|
229
|
+
- Treating BOOKED (status 11) tickets as current — they are terminal; the open set excludes `[8,9,10,11]`.
|
|
230
|
+
- Logging time against a user id you guessed — always read `sub` from `whoami`.
|
|
@@ -5,7 +5,9 @@ description: Manage ZeyOS tickets, tasks, projects, action steps, assignees, and
|
|
|
5
5
|
|
|
6
6
|
# ZeyOS Work Management
|
|
7
7
|
|
|
8
|
-
Read [../shared/zeyos-query-patterns.md](../shared/zeyos-query-patterns.md) first. Read [../shared/zeyos-entity-map.md](../shared/zeyos-entity-map.md) when the request crosses users, accounts, tickets, tasks, and projects. Read [references/workflows.md](references/workflows.md) for the concrete query patterns.
|
|
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. Read [../shared/zeyos-entity-map.md](../shared/zeyos-entity-map.md) when the request crosses users, accounts, tickets, tasks, and projects. Read [references/workflows.md](references/workflows.md) for the concrete query patterns.
|
|
9
|
+
|
|
10
|
+
For **first-person** requests ("what are *my* current tickets?", "my open tasks") or for **recording new time** ("log 60 minutes for client XYZ"), use [../zeyos-time-tracking/SKILL.md](../zeyos-time-tracking/SKILL.md) instead — it resolves the current user and runs the interactive account → work-item → time-entry flow. This skill stays focused on third-person analytical queues, tracing, and effort *summaries*.
|
|
9
11
|
|
|
10
12
|
Typical prompts:
|
|
11
13
|
|
|
@@ -13,6 +15,7 @@ Typical prompts:
|
|
|
13
15
|
- "Show overdue high-priority tickets for customer ACME."
|
|
14
16
|
- "Which open tasks are blocking Project Atlas?"
|
|
15
17
|
- "Which action steps are due this week for ACME?"
|
|
18
|
+
- "How much booked effort did this user log last week?"
|
|
16
19
|
- "Create a follow-up ticket for this billing issue."
|
|
17
20
|
|
|
18
21
|
## Workflow
|
|
@@ -22,10 +25,10 @@ Typical prompts:
|
|
|
22
25
|
3. Start with the narrowest query that can answer the question:
|
|
23
26
|
- use `tickets` for queue, backlog, priority, and account-linked support work
|
|
24
27
|
- use `tasks` for actionable delivery work and short-lived assignments
|
|
25
|
-
- use `actionsteps` for smaller cross-record follow-ups attached to tasks, tickets, accounts, or transactions
|
|
28
|
+
- use `actionsteps` for smaller cross-record follow-ups and effort/time-entry evidence attached to tasks, tickets, accounts, or transactions
|
|
26
29
|
- use `projects` for top-level initiative state
|
|
27
30
|
4. Follow relationships only after the primary record set is clear.
|
|
28
|
-
5. Treat "worked on" as a proxy unless
|
|
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.
|
|
29
32
|
6. Distinguish direct project assignment from project inference through linked tickets.
|
|
30
33
|
7. When the question is really about account or transaction follow-up, check `actionsteps` before inventing a new task.
|
|
31
34
|
8. For mutations, preview the affected record first and update with an explicit PATCH body.
|
|
@@ -9,10 +9,20 @@
|
|
|
9
9
|
- `users`: system identities for assignees
|
|
10
10
|
|
|
11
11
|
These are dbref nouns, not operationIds. Note `actionsteps` -> `listActionSteps` /
|
|
12
|
-
`getActionStep` / `createActionStep`
|
|
12
|
+
`getActionStep` / `createActionStep` / `updateActionStep` / `deleteActionStep`
|
|
13
|
+
(compound CamelCase, not `listActionsteps`). See
|
|
13
14
|
[../../shared/zeyos-entity-reference.md](../../shared/zeyos-entity-reference.md#entity-noun-to-rest-operationid)
|
|
14
15
|
before calling `@zeyos/client`.
|
|
15
16
|
|
|
17
|
+
Actionstep status values:
|
|
18
|
+
|
|
19
|
+
- `0` = DRAFT / open follow-up
|
|
20
|
+
- `1` = COMPLETED
|
|
21
|
+
- `2` = CANCELLED
|
|
22
|
+
- `3` = BOOKED
|
|
23
|
+
|
|
24
|
+
Use `effort` as minutes of effort only when the question is about time entries or booked/completed work. Do not infer booked time from task assignment alone.
|
|
25
|
+
|
|
16
26
|
## Resolve Before Querying
|
|
17
27
|
|
|
18
28
|
1. Resolve the user or account first.
|
|
@@ -32,7 +42,7 @@ Recommended approach:
|
|
|
32
42
|
1. Resolve the user from `users.name` or `users.email`.
|
|
33
43
|
2. Query recent tasks assigned to that user with `lastmodified > cutoff`.
|
|
34
44
|
3. Query recent tickets assigned to that user with `lastmodified > cutoff`.
|
|
35
|
-
4.
|
|
45
|
+
4. Query recent `actionsteps` for the same user when you need stronger evidence of follow-up activity or booked effort.
|
|
36
46
|
5. Collect direct `project` links from tasks and tickets.
|
|
37
47
|
6. For tasks that only link to a ticket, fetch the ticket or include `ticket.project` if available in the selected fields.
|
|
38
48
|
7. For action steps linked to tasks or tickets, infer the project through the linked parent only if the user asked for a broad activity summary.
|
|
@@ -67,7 +77,7 @@ const recentTickets = await client.api.listTickets({
|
|
|
67
77
|
|
|
68
78
|
Important caveat:
|
|
69
79
|
|
|
70
|
-
-
|
|
80
|
+
- Assignment-based "worked on" answers are activity proxies. `actionsteps` with `date`, `status` COMPLETED/BOOKED, and `effort` are the better evidence for time-entry summaries.
|
|
71
81
|
|
|
72
82
|
## Pattern: Review A Ticket Queue
|
|
73
83
|
|
|
@@ -87,6 +97,13 @@ zeyos list tickets \
|
|
|
87
97
|
Follow up with `tasks` only if the answer requires execution detail below the ticket level.
|
|
88
98
|
Follow up with `actionsteps` if the queue management style in this instance uses reminders or next steps below the ticket.
|
|
89
99
|
|
|
100
|
+
For ticket work packets, include:
|
|
101
|
+
|
|
102
|
+
- ticket status, priority, due date, account/project links
|
|
103
|
+
- open tasks linked by `task.ticket`
|
|
104
|
+
- open actionsteps linked by `actionstep.ticket` or by task
|
|
105
|
+
- recent messages linked by `message.ticket` if the request asks for customer context
|
|
106
|
+
|
|
90
107
|
## Pattern: Overdue Work For An Account Or Project
|
|
91
108
|
|
|
92
109
|
Use this for prompts like:
|
|
@@ -121,6 +138,39 @@ Recommended approach:
|
|
|
121
138
|
4. Keep due date and status visible in the result.
|
|
122
139
|
5. If the anchor is a transaction and the user also wants broader work context, then check related tickets or account-level tasks second.
|
|
123
140
|
|
|
141
|
+
CLI examples:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
zeyos list actionsteps \
|
|
145
|
+
--fields ID,actionnum,name,status,date,duedate,effort,ticket,task,account,transaction \
|
|
146
|
+
--filter '{"ticket":812}' \
|
|
147
|
+
--sort +duedate \
|
|
148
|
+
--limit 100 \
|
|
149
|
+
--json
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
For counts:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
zeyos count actionsteps --filter '{"ticket":812,"status":0}' --json
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Pattern: Time Entry / Effort Summaries
|
|
159
|
+
|
|
160
|
+
Use this for prompts like:
|
|
161
|
+
|
|
162
|
+
- "How many minutes were booked on ticket 812 last week?"
|
|
163
|
+
- "Summarize completed actionstep effort for this account."
|
|
164
|
+
- "Which user logged effort against this project?"
|
|
165
|
+
|
|
166
|
+
Recommended approach:
|
|
167
|
+
|
|
168
|
+
1. Resolve the anchor and the date window.
|
|
169
|
+
2. Query `actionsteps` with fields `ID`, `date`, `status`, `effort`, and the relevant FK (`ticket`, `task`, `account`, or `transaction`).
|
|
170
|
+
3. Include statuses `1` COMPLETED and `3` BOOKED for time-entry totals unless the user asks for drafts/open follow-ups.
|
|
171
|
+
4. Sum `effort` as minutes; convert to hours only if the user asked for hours.
|
|
172
|
+
5. Keep task/ticket assignment separate from effort totals.
|
|
173
|
+
|
|
124
174
|
## Pattern: Create Follow-Up Work
|
|
125
175
|
|
|
126
176
|
For prompts like:
|
|
@@ -136,7 +186,7 @@ Recommended approach:
|
|
|
136
186
|
- use `project` if the follow-up is project-wide
|
|
137
187
|
- use `actionsteps` if the follow-up is small, account-scoped, or transaction-scoped and does not justify a standalone task
|
|
138
188
|
- keep `visibility: 0`
|
|
139
|
-
3. Confirm the new owner, due date, and priority if they are not explicit.
|
|
189
|
+
3. Confirm the new owner, due date, and priority/effort if they are not explicit.
|
|
140
190
|
4. Use explicit PATCH or create bodies and return the created record ID.
|
|
141
191
|
|
|
142
192
|
## Common Failure Modes
|
|
@@ -253,6 +253,26 @@ const page2 = await client.api.listTickets({
|
|
|
253
253
|
Use `count: true` to get the total number of matching records without fetching the full dataset. This is useful for building pagination controls.
|
|
254
254
|
:::
|
|
255
255
|
|
|
256
|
+
### Auto-pagination
|
|
257
|
+
|
|
258
|
+
To iterate an entire result set without managing `offset` yourself, use `client.paginate(operationId, input, opts)` — an async iterator that pages until a short/empty page (or `opts.max`) is reached. It removes the off-by-one and "I only got the first 1000 / 50 rows" mistakes the list caps otherwise invite.
|
|
259
|
+
|
|
260
|
+
```js
|
|
261
|
+
// Stream every matching ticket, one page at a time
|
|
262
|
+
for await (const ticket of client.paginate('listTickets', { filters: { visibility: 0 } }, { pageSize: 1000 })) {
|
|
263
|
+
process(ticket);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Eagerly collect up to a cap
|
|
267
|
+
const recent = await client.collect(
|
|
268
|
+
'listTickets',
|
|
269
|
+
{ filters: { visibility: 0 }, sort: ['-lastmodified'] },
|
|
270
|
+
{ pageSize: 500, max: 2000 }
|
|
271
|
+
);
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
`opts`: `pageSize` (default 1000, clamped to the server max of 10000), `max` (stop after N records), and `requestOptions` (forwarded to each underlying call, e.g. `{ signal, timeoutMs }`). `collect` is the eager array form of `paginate`.
|
|
275
|
+
|
|
256
276
|
## Normalising List Responses
|
|
257
277
|
|
|
258
278
|
List endpoints are not uniform across the full surface area. Depending on the endpoint and response mode, you may see:
|
|
@@ -432,9 +452,32 @@ const noRetry = createZeyosClient({ platform: 'live', instance: 'demo', retry: f
|
|
|
432
452
|
Only `429`/`503` are retried by default -- statuses that clearly mean "try again later". `5xx` codes such as `500`/`502` are **not** retried automatically, to avoid re-applying a non-idempotent write that may have partially succeeded. Add them to `retryOn` only for read-heavy workloads.
|
|
433
453
|
:::
|
|
434
454
|
|
|
455
|
+
### Request timeout
|
|
456
|
+
|
|
457
|
+
A request with no built-in deadline can hang indefinitely if the connection stalls (e.g. an instance restarting). Set `timeoutMs` to bound each attempt; it composes with any `AbortSignal` you pass. The timeout applies **per attempt**, so a retry gets a fresh deadline.
|
|
458
|
+
|
|
459
|
+
```js
|
|
460
|
+
// Per request
|
|
461
|
+
await client.api.listTickets({ filters: { visibility: 0 } }, { timeoutMs: 8000 });
|
|
462
|
+
|
|
463
|
+
// Or a client-wide default
|
|
464
|
+
const client = createZeyosClient({ platform: 'live', instance: 'demo', timeoutMs: 8000 });
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
A timeout rejects with an `Error` whose `isTimeout === true` (and `code === 'ETIMEDOUT'`). A timeout is distinct from a caller abort: aborting your own `AbortSignal` always propagates immediately and is never retried.
|
|
468
|
+
|
|
469
|
+
### Network-error retries
|
|
470
|
+
|
|
471
|
+
Network-level failures (a dropped connection, DNS blip, or a timeout) are retried for **read** operations only — `GET`/`HEAD` plus side-effect-free `list`/`count`/`search` queries — using the same retry budget and backoff. Writes (`create`/`update`/`delete`) are **never** auto-retried on a network error, so a dropped connection can't cause a duplicate mutation. Override per request or per client with `retryOnNetworkError: true | false`.
|
|
472
|
+
|
|
473
|
+
```js
|
|
474
|
+
await client.api.listTickets({ filters: {} }, { retryOnNetworkError: true }); // force (already on for reads)
|
|
475
|
+
await client.api.createTicket({ name: 'x' }, { retryOnNetworkError: true }); // opt a write in, at your own risk
|
|
476
|
+
```
|
|
477
|
+
|
|
435
478
|
## Error Handling
|
|
436
479
|
|
|
437
|
-
All API errors are thrown as `ZeyosApiError` instances. This class extends `Error` and includes structured information about the failed request.
|
|
480
|
+
All API errors are thrown as `ZeyosApiError` instances. This class extends `Error` and includes structured information about the failed request. When the server returns an error body with a message, a short snippet of it is folded into `err.message` (e.g. `api.listTickets failed with HTTP 400: unknown filter field: bogus`), so the thrown error says *why*, not just the status code. The full body is always on `err.body`.
|
|
438
481
|
|
|
439
482
|
```js
|
|
440
483
|
import { ZeyosApiError } from '@zeyos/client';
|
|
@@ -535,6 +578,8 @@ All generated methods and `client.request()` accept an optional second argument
|
|
|
535
578
|
| Option | Type | Description |
|
|
536
579
|
|--------|------|-------------|
|
|
537
580
|
| `signal` | `AbortSignal` | An `AbortController` signal to cancel the request |
|
|
581
|
+
| `timeoutMs` | `number` | Abort this attempt after N ms (composes with `signal`); also settable client-wide as `timeoutMs` |
|
|
582
|
+
| `retryOnNetworkError` | `boolean` | Force/disable retrying network errors & timeouts for this call (default: on for reads, off for writes) |
|
|
538
583
|
| `raw` | `boolean` | Return the full response envelope instead of just the data |
|
|
539
584
|
| `auth` | `string \| { mode?: string, accessToken?: string, access_token?: string, refreshToken?: string, refresh_token?: string, clientId?: string, client_id?: string, clientSecret?: string, client_secret?: string }` | Override the authentication mode or credentials for this request |
|
|
540
585
|
| `baseUrl` | `string` | Override the base URL for this request |
|
|
@@ -143,6 +143,13 @@ zeyos list tickets --filter '{"status":1,"priority":3}'
|
|
|
143
143
|
zeyos count tickets --filter '{"status":1}'
|
|
144
144
|
```
|
|
145
145
|
|
|
146
|
+
For larger filters, store the JSON in a file and use `--filter-file`:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
zeyos list tickets --filter-file ./filters/open-tickets.json --json
|
|
150
|
+
zeyos count tickets --filter-file ./filters/open-tickets.json --json
|
|
151
|
+
```
|
|
152
|
+
|
|
146
153
|
For normal operational views, include `visibility: 0`:
|
|
147
154
|
|
|
148
155
|
```bash
|