trackly-cli 0.8.1 → 0.9.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 +2 -2
- package/lib/agent.js +1 -1
- package/mcp/apply-tools.js +4 -4
- package/npm-shrinkwrap.json +12 -12
- package/package.json +6 -3
- package/scripts/verify-audit-exceptions.js +6 -31
- package/security/audit-exceptions.json +1 -67
- package/server.json +2 -2
- package/skills/trackly-apply/SKILL.md +8 -6
- package/skills/trackly-apply/references/ats-playbook.md +6 -0
- package/skills/trackly-apply/references/batch-orchestration.md +35 -10
- package/skills/trackly-apply/references/browser-lifecycle.md +8 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[](https://www.npmjs.com/package/trackly-cli)
|
|
2
2
|
[](https://opensource.org/licenses/MIT)
|
|
3
|
-
[](https://nodejs.org/)
|
|
4
4
|
[](https://modelcontextprotocol.io/)
|
|
5
5
|
|
|
6
6
|
# trackly-cli
|
|
@@ -31,7 +31,7 @@ trackly login
|
|
|
31
31
|
trackly jobs --function product
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
> **Prerequisites:** [Node.js
|
|
34
|
+
> **Prerequisites:** [Node.js 20+](https://nodejs.org/) (LTS recommended). On macOS with the official `.pkg` installer, global npm installs may require `sudo`.
|
|
35
35
|
|
|
36
36
|
## At a Glance
|
|
37
37
|
|
package/lib/agent.js
CHANGED
|
@@ -8,7 +8,7 @@ const { spawnSync } = require('node:child_process');
|
|
|
8
8
|
const { apiRequest, downloadFile, getConfigPaths, hasAuth, maintenanceOutput } = require('./client');
|
|
9
9
|
const { version: PACKAGE_VERSION } = require('../package.json');
|
|
10
10
|
const { contractVersion: MCP_CONTRACT_VERSION } = require('../contracts/trackly-apply-tools.json');
|
|
11
|
-
const SKILL_VERSION = '4.2.
|
|
11
|
+
const SKILL_VERSION = '4.2.3';
|
|
12
12
|
const CLI_USER_AGENT = `trackly-cli/${PACKAGE_VERSION}`;
|
|
13
13
|
const MCP_USER_AGENT = `trackly-mcp/${PACKAGE_VERSION}`;
|
|
14
14
|
|
package/mcp/apply-tools.js
CHANGED
|
@@ -561,7 +561,7 @@ function registerApplyTools(
|
|
|
561
561
|
|
|
562
562
|
server.tool(
|
|
563
563
|
'trackly_record_application_outcome',
|
|
564
|
-
'Record review readiness or a user-confirmed outcome. Mark submitted only after a success page or explicit user confirmation.',
|
|
564
|
+
'Record review readiness or a user-confirmed outcome. Before handoff use literal outcome=review_ready and verify awaiting_manual_submit. Mark submitted with literal outcome=submitted only after a success page or explicit user confirmation.',
|
|
565
565
|
{
|
|
566
566
|
runId: z.number().int().min(1),
|
|
567
567
|
batchId: z.number().int().min(1).optional(),
|
|
@@ -576,7 +576,7 @@ function registerApplyTools(
|
|
|
576
576
|
|
|
577
577
|
server.tool(
|
|
578
578
|
'trackly_record_application_outcomes',
|
|
579
|
-
'Bulk-record up to 20 leased, batch-bound review or user-confirmed outcomes. Each member returns recorded or conflict without hiding sibling results.',
|
|
579
|
+
'Bulk-record up to 20 leased, batch-bound review or user-confirmed outcomes. Before handoff every item uses literal outcome=review_ready and every recorded run must return awaiting_manual_submit. After manual confirmation use literal outcome=submitted. Each member returns recorded or a stable conflict without hiding sibling results.',
|
|
580
580
|
{
|
|
581
581
|
outcomes: z.array(z.object({
|
|
582
582
|
runId: z.number().int().min(1),
|
|
@@ -636,13 +636,13 @@ function registerApplyTools(
|
|
|
636
636
|
role: 'user',
|
|
637
637
|
content: {
|
|
638
638
|
type: 'text',
|
|
639
|
-
text: 'Compatibility and batch gate: require Trackly Apply protocol 3.3.1 or newer and skill 4.2.
|
|
639
|
+
text: 'Compatibility and batch gate: require Trackly Apply protocol 3.3.1 or newer and skill 4.2.3 or newer for every new frozen batch. Protocol 3.2 remains valid for the explicit legacy single-run workflow. Recover the active frozen batch before creating another, including for a one-job request. Do not fetch or select from the queue until active-batch recovery proves that no active batch exists; any later generic queue-first instruction applies only to the legacy 3.2 single-run workflow. Claim its lease, keep membership/order fixed, inspect all members before asking one grouped packet of questions, bind each initial or recovered browser surface to the same run and exact backend URL, and discard older-epoch evidence. If a bound start returns a transport failure, a non-access HTTP 5xx response, or an error explicitly marked retryable true, preserve the frozen member and browser state, refetch the same active batch, renew its lease, and retry the same complete binding exactly once. Classify the retry response independently with the same rules: route maintenance_mode or planned_maintenance from either attempt through maintenance recovery, surface controlled-access/request errors marked retryable false and every other HTTP 4xx response unchanged, and only classify a second transport failure, non-access HTTP 5xx response, or explicitly retryable error as backend_run_start_unavailable. Never relabel a permanent retry response as an outage. Preserve the unchanged frozen member as the durable resume point, continue siblings after backend_run_start_unavailable, and never checkpoint the pre-run failure or detach it into an unbound legacy run. Require one exact batch resume approval plus immediate local proof before each attachment; ordinary member-version checkpoints do not revoke unchanged resume-content approval. If no form in a truth-certified subset exposes a resume control, certify truth with resumeDependency not_applicable and no resume identity. After durable review-ready checkpoints, truth-certify the exact complete subset, bulk-record literal outcome=review_ready for every member, and verify every recorded run returns awaiting_manual_submit before handoff without waiting for needs-input members. Keep unresolved members frozen and resumable; when another member becomes ready later, create a fresh certification for the then-current complete review-ready subset. After manual Submit, keep submission request, success-page or explicit user-confirmation, provider receipt, and three-part surface-close proof separate and redacted, then record literal outcome=submitted. Treat submission reconciliation as a durable commit gate: keep the confirmation tab open until a refetch proves member lifecycle submitted and Trackly job state applied_confirmed.',
|
|
640
640
|
},
|
|
641
641
|
}, {
|
|
642
642
|
role: 'user',
|
|
643
643
|
content: {
|
|
644
644
|
type: 'text',
|
|
645
|
-
text: 'Fetch the Trackly Apply protocol, profile onboarding, profile, and approved queue. Resolve missing answers with me. Treat required completeness separately from optional reusable coverage and employer-specific contextual questions. Before starting anything, stop on every non-null executionBlocker and every manual_only item. Start only the selected approved queue item, require major(run.protocolVersion) === major(protocol.version), require protocol.compatibleSkillMajor === 4, preserve the stored version for a resumed run, and require its provider, atsCapability, required scenarios, and originPolicy to match the queue preflight. Reclaim semantic browser control, verify the exact job/run/tab binding, hash that value-free binding, and report the same-run browser_ready attestation with committed=true. Before entering private data, require the visible company and role to match the run binding and, when available, the requisition identifier to match the stored job URL. When job_identity_match is required, report a value-free committed scenario_coverage attestation only after that visible identity check passes; never include the company, role, URL, requisition identifier, page text, or any profile value in that observation. On exact-origin fallback, revalidate the frozen company, role, and available requisition identity after every navigation or redirect and before entering any additional private data. Normalize every page, redirect, and data-receiving iframe URL; accept an exact authorized origin or hostname only when host === allowedDomain or host.endsWith("." + allowedDomain), never by substring or page text. When originPolicy.verification is trackly_employer_source_exact_origin, authorize only the exact origin in authorizedOrigins: never promote it to a host suffix and never carry it across a redirect or iframe origin change. For every other vendor-hosted ATS policy, require both originPolicy.tenantRule and originPolicy.verifiedAtsTenant to be non-null or stop before private data entry. Execute the backend-owned originPolicy.tenantRule exactly after every redirect or data-receiving iframe change, including its extraction, exact-host-depth, locale, percent-decoding, normalization, and fail-closed semantics, then require the normalized result to equal originPolicy.verifiedAtsTenant; never invent or reinterpret a strategy token. Obey every capability stop condition. Determine whether the form has a semantically identified Resume or CV attachment control. Only when that specific control exists, prepare the run-bound resume locally with that browser surface and binding hash, show me its exact path, filename, size, SHA-256, run, and expiration, and obtain my explicit confirmation. Treat cover-letter, portfolio, transcript, and other supporting-document controls separately according to the profile and protocol; never upload a resume to them. Immediately before attaching the resume, use the local verifier to validate the signed proof, recompute hash and size, check expiration, and lock the file read-only. Fill the
|
|
645
|
+
text: 'Fetch the Trackly Apply protocol, profile onboarding, profile, and approved queue. Resolve missing answers with me. Treat required completeness separately from optional reusable coverage and employer-specific contextual questions. Before starting anything, stop on every non-null executionBlocker and every manual_only item. Start only the selected approved queue item, require major(run.protocolVersion) === major(protocol.version), require protocol.compatibleSkillMajor === 4, preserve the stored version for a resumed run, and require its provider, atsCapability, required scenarios, and originPolicy to match the queue preflight. Reclaim semantic browser control, verify the exact job/run/tab binding, hash that value-free binding, and report the same-run browser_ready attestation with committed=true. Before entering private data, require the visible company and role to match the run binding and, when available, the requisition identifier to match the stored job URL. When job_identity_match is required, report a value-free committed scenario_coverage attestation only after that visible identity check passes; never include the company, role, URL, requisition identifier, page text, or any profile value in that observation. On exact-origin fallback, revalidate the frozen company, role, and available requisition identity after every navigation or redirect and before entering any additional private data. Normalize every page, redirect, and data-receiving iframe URL; accept an exact authorized origin or hostname only when host === allowedDomain or host.endsWith("." + allowedDomain), never by substring or page text. When originPolicy.verification is trackly_employer_source_exact_origin, authorize only the exact origin in authorizedOrigins: never promote it to a host suffix and never carry it across a redirect or iframe origin change. For every other vendor-hosted ATS policy, require both originPolicy.tenantRule and originPolicy.verifiedAtsTenant to be non-null or stop before private data entry. Execute the backend-owned originPolicy.tenantRule exactly after every redirect or data-receiving iframe change, including its extraction, exact-host-depth, locale, percent-decoding, normalization, and fail-closed semantics, then require the normalized result to equal originPolicy.verifiedAtsTenant; never invent or reinterpret a strategy token. Obey every capability stop condition. Determine whether the form has a semantically identified Resume or CV attachment control. Only when that specific control exists, prepare the run-bound resume locally with that browser surface and binding hash, show me its exact path, filename, size, SHA-256, run, and expiration, and obtain my explicit confirmation. Treat cover-letter, portfolio, transcript, and other supporting-document controls separately according to the profile and protocol; never upload a resume to them. Immediately before attaching the resume, use the local verifier to validate the signed proof, recompute hash and size, check expiration, and lock the file read-only. Fill every visible field whose answer is already known, including optional fields, before asking one grouped packet for the remaining unknowns. Use real semantic UI actions and the provider playbook for Greenhouse, Ashby, HiBob, or the active capability; after every select, radio, checkbox, masked input, and upload, verify the committed DOM or accessibility state and that any related required error disappeared. Then sweep all required fields, duplicate contact values, correction banners, and the final consent control. Report a same-run passed or corrected scenario_coverage observation with committed=true for every backend-required scenario except browser_reclaim, which is satisfied only by browser_ready with the binding hash. Before every review_ready outcome, also report value-free committed critical_contact_integrity and manual_submit_boundary evidence; never include contact values, answers, page text, or local paths. If a required or universal review scenario cannot pass, record blocked rather than review_ready. Stop before Submit. If maintenance interrupts the run, retain the run and browser context, wait for the advertised window, refetch protocol, queue, and profile state, and resume the existing agent_browser run. Never start a duplicate run, blindly retry a mutation, enter credentials or verification codes, evade human verification, or click Submit.',
|
|
646
646
|
},
|
|
647
647
|
}],
|
|
648
648
|
}));
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "trackly-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "trackly-cli",
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.9.1",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@modelcontextprotocol/sdk": "
|
|
12
|
+
"@modelcontextprotocol/sdk": "1.30.0",
|
|
13
13
|
"hono": "^4.12.30",
|
|
14
14
|
"zod": "^3.23.0"
|
|
15
15
|
},
|
|
@@ -17,28 +17,28 @@
|
|
|
17
17
|
"trackly": "bin/trackly"
|
|
18
18
|
},
|
|
19
19
|
"engines": {
|
|
20
|
-
"node": ">=
|
|
20
|
+
"node": ">=20"
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
23
|
"node_modules/@hono/node-server": {
|
|
24
|
-
"version": "
|
|
25
|
-
"resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-
|
|
26
|
-
"integrity": "sha512-
|
|
24
|
+
"version": "2.0.12",
|
|
25
|
+
"resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-2.0.12.tgz",
|
|
26
|
+
"integrity": "sha512-eWpQYr67tqJLeaSUl0Q+TquuYfUdTibpOJlUMV2FfUP7+KqCC5TufnwnlXL6mobZBJbGAYRd7ZvEBDCbLInjhg==",
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"engines": {
|
|
29
|
-
"node": ">=
|
|
29
|
+
"node": ">=20"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
32
|
"hono": "^4"
|
|
33
33
|
}
|
|
34
34
|
},
|
|
35
35
|
"node_modules/@modelcontextprotocol/sdk": {
|
|
36
|
-
"version": "1.
|
|
37
|
-
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.
|
|
38
|
-
"integrity": "sha512-
|
|
36
|
+
"version": "1.30.0",
|
|
37
|
+
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.30.0.tgz",
|
|
38
|
+
"integrity": "sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==",
|
|
39
39
|
"license": "MIT",
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@hono/node-server": "^1.19.9",
|
|
41
|
+
"@hono/node-server": "^1.19.9 || ^2.0.5",
|
|
42
42
|
"ajv": "^8.17.1",
|
|
43
43
|
"ajv-formats": "^3.0.1",
|
|
44
44
|
"content-type": "^1.0.5",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "trackly-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"mcpName": "io.github.trackly-app/trackly",
|
|
5
5
|
"description": "AI job search CLI + hosted MCP server with OAuth. 128K+ jobs, 1,900+ companies, 40+ ATS. Works with Claude, ChatGPT, Cursor, Windsurf, Codex via hosted streamable-http or local stdio.",
|
|
6
6
|
"bin": {
|
|
@@ -62,11 +62,14 @@
|
|
|
62
62
|
"url": "https://github.com/trackly-app/trackly-cli/issues"
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
|
-
"@modelcontextprotocol/sdk": "
|
|
65
|
+
"@modelcontextprotocol/sdk": "1.30.0",
|
|
66
66
|
"hono": "^4.12.30",
|
|
67
67
|
"zod": "^3.23.0"
|
|
68
68
|
},
|
|
69
69
|
"engines": {
|
|
70
|
-
"node": ">=
|
|
70
|
+
"node": ">=20"
|
|
71
|
+
},
|
|
72
|
+
"overrides": {
|
|
73
|
+
"@hono/node-server": "2.0.12"
|
|
71
74
|
}
|
|
72
75
|
}
|
|
@@ -70,21 +70,9 @@ function validatePolicy(policy) {
|
|
|
70
70
|
assert.ok(Array.isArray(policy.exceptions));
|
|
71
71
|
assert.equal(
|
|
72
72
|
policy.exceptions.length,
|
|
73
|
-
|
|
74
|
-
'
|
|
73
|
+
0,
|
|
74
|
+
'No npm audit exceptions are permitted',
|
|
75
75
|
);
|
|
76
|
-
const exception = policy.exceptions[0];
|
|
77
|
-
assert.equal(exception.advisory, 'GHSA-frvp-7c67-39w9');
|
|
78
|
-
assert.equal(exception.package, '@hono/node-server');
|
|
79
|
-
assert.equal(exception.dependencyOf, '@modelcontextprotocol/sdk');
|
|
80
|
-
assert.equal(exception.severity, 'moderate');
|
|
81
|
-
assert.equal(exception.vulnerableRange, '<2.0.5');
|
|
82
|
-
assert.equal(
|
|
83
|
-
exception.upstream,
|
|
84
|
-
'https://github.com/modelcontextprotocol/typescript-sdk/issues/2531',
|
|
85
|
-
);
|
|
86
|
-
assert.ok(exception.expectedAuditShape);
|
|
87
|
-
return exception;
|
|
88
76
|
}
|
|
89
77
|
|
|
90
78
|
function validateAuditReport(report, policy) {
|
|
@@ -106,7 +94,7 @@ function validateAuditReport(report, policy) {
|
|
|
106
94
|
);
|
|
107
95
|
}
|
|
108
96
|
assert.equal(report?.auditReportVersion, 2, 'Unsupported npm audit report version');
|
|
109
|
-
|
|
97
|
+
validatePolicy(policy);
|
|
110
98
|
|
|
111
99
|
if (cleanAuditResult(report)) {
|
|
112
100
|
return {
|
|
@@ -114,22 +102,9 @@ function validateAuditReport(report, policy) {
|
|
|
114
102
|
propagatedVulnerabilities: [],
|
|
115
103
|
};
|
|
116
104
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
} catch (error) {
|
|
121
|
-
const wrapped = new Error(
|
|
122
|
-
'npm audit report does not match the temporary exception. '
|
|
123
|
-
+ 'Review every new advisory, severity, affected range, and dependency-path change.',
|
|
124
|
-
);
|
|
125
|
-
wrapped.cause = error;
|
|
126
|
-
throw wrapped;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return {
|
|
130
|
-
allowedAdvisories: [exception.advisory],
|
|
131
|
-
propagatedVulnerabilities: Object.keys(report.vulnerabilities).sort(),
|
|
132
|
-
};
|
|
105
|
+
throw new Error(
|
|
106
|
+
'npm audit reported a vulnerability; Trackly CLI permits no audit exceptions.',
|
|
107
|
+
);
|
|
133
108
|
}
|
|
134
109
|
|
|
135
110
|
function loadPolicy(policyPath = DEFAULT_POLICY_PATH) {
|
|
@@ -1,70 +1,4 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"exceptions": [
|
|
4
|
-
{
|
|
5
|
-
"advisory": "GHSA-frvp-7c67-39w9",
|
|
6
|
-
"source": 1124006,
|
|
7
|
-
"package": "@hono/node-server",
|
|
8
|
-
"dependencyOf": "@modelcontextprotocol/sdk",
|
|
9
|
-
"severity": "moderate",
|
|
10
|
-
"vulnerableRange": "<2.0.5",
|
|
11
|
-
"upstream": "https://github.com/modelcontextprotocol/typescript-sdk/issues/2531",
|
|
12
|
-
"rationale": "Trackly starts the MCP SDK only through its stdio transport. It does not import @hono/node-server, Streamable HTTP, or serveStatic, so the Windows static-file path traversal is unreachable. Automated stdio isolation and packed-consumer tests enforce that boundary until the SDK removes or upgrades this dependency.",
|
|
13
|
-
"expectedAuditShape": {
|
|
14
|
-
"vulnerabilityCounts": {
|
|
15
|
-
"info": 0,
|
|
16
|
-
"low": 0,
|
|
17
|
-
"moderate": 2,
|
|
18
|
-
"high": 0,
|
|
19
|
-
"critical": 0,
|
|
20
|
-
"total": 2
|
|
21
|
-
},
|
|
22
|
-
"vulnerabilities": {
|
|
23
|
-
"@hono/node-server": {
|
|
24
|
-
"name": "@hono/node-server",
|
|
25
|
-
"severity": "moderate",
|
|
26
|
-
"isDirect": false,
|
|
27
|
-
"via": [
|
|
28
|
-
{
|
|
29
|
-
"source": 1124006,
|
|
30
|
-
"name": "@hono/node-server",
|
|
31
|
-
"dependency": "@hono/node-server",
|
|
32
|
-
"title": "Node.js Adapter for Hono: Path traversal in `serve-static` on Windows via encoded backslash (`%5C`)",
|
|
33
|
-
"url": "https://github.com/advisories/GHSA-frvp-7c67-39w9",
|
|
34
|
-
"severity": "moderate",
|
|
35
|
-
"cwe": [
|
|
36
|
-
"CWE-22"
|
|
37
|
-
],
|
|
38
|
-
"cvss": {
|
|
39
|
-
"score": 5.9,
|
|
40
|
-
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N"
|
|
41
|
-
},
|
|
42
|
-
"range": "<2.0.5"
|
|
43
|
-
}
|
|
44
|
-
],
|
|
45
|
-
"effects": [
|
|
46
|
-
"@modelcontextprotocol/sdk"
|
|
47
|
-
],
|
|
48
|
-
"range": "<2.0.5",
|
|
49
|
-
"nodes": [
|
|
50
|
-
"node_modules/@hono/node-server"
|
|
51
|
-
]
|
|
52
|
-
},
|
|
53
|
-
"@modelcontextprotocol/sdk": {
|
|
54
|
-
"name": "@modelcontextprotocol/sdk",
|
|
55
|
-
"severity": "moderate",
|
|
56
|
-
"isDirect": true,
|
|
57
|
-
"via": [
|
|
58
|
-
"@hono/node-server"
|
|
59
|
-
],
|
|
60
|
-
"effects": [],
|
|
61
|
-
"range": ">=1.25.0",
|
|
62
|
-
"nodes": [
|
|
63
|
-
"node_modules/@modelcontextprotocol/sdk"
|
|
64
|
-
]
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
]
|
|
3
|
+
"exceptions": []
|
|
70
4
|
}
|
package/server.json
CHANGED
|
@@ -17,12 +17,12 @@
|
|
|
17
17
|
]
|
|
18
18
|
}
|
|
19
19
|
],
|
|
20
|
-
"version": "0.
|
|
20
|
+
"version": "0.9.1",
|
|
21
21
|
"packages": [
|
|
22
22
|
{
|
|
23
23
|
"registryType": "npm",
|
|
24
24
|
"identifier": "trackly-cli",
|
|
25
|
-
"version": "0.
|
|
25
|
+
"version": "0.9.1",
|
|
26
26
|
"runtimeHint": "npx",
|
|
27
27
|
"runtimeArguments": [
|
|
28
28
|
{
|
|
@@ -25,7 +25,7 @@ Before selecting or resuming work, read
|
|
|
25
25
|
references define the server-frozen batch, grouped-question, tab-reconciliation,
|
|
26
26
|
and missing-surface recovery contract; they are mandatory even for a one-job batch.
|
|
27
27
|
|
|
28
|
-
1. Call `trackly_get_apply_protocol`. Skill 4.2.
|
|
28
|
+
1. Call `trackly_get_apply_protocol`. Skill 4.2.3 requires protocol major 3 and protocol 3.3.1 or newer for frozen-batch execution; protocol 3.2 remains valid for the explicit legacy single-run workflow. Require `compatibleSkillMajor: 4` and `compatibleSkillMinimumVersion` no newer than this installed skill. Reject an older or incompatible version and report that the backend must finish updating or `trackly agent setup` must update the skill. Protocol 3.2 added exact-origin trust for jobs Trackly ingested directly from employer careers sources; do not recreate the retired ownership-timestamp gate in the client.
|
|
29
29
|
2. Call `trackly_get_profile_onboarding` or fetch both the profile schema and application profile. Treat `completeness.percent` as required onboarding readiness only. Use `coverage.missingReusableKeys` to explain reusable optional gaps, while `coverage.contextualKeys` are intentionally asked only on the relevant employer form. Do not claim that 100% required completeness answers every possible application question.
|
|
30
30
|
3. Save answers with `trackly_update_application_profile`:
|
|
31
31
|
- Use `answered`, `intentionally_blank`, `declined`, or `unknown` exactly.
|
|
@@ -47,7 +47,8 @@ and missing-surface recovery contract; they are mandatory even for a one-job bat
|
|
|
47
47
|
- If the user requests the next `N` jobs, freeze up to `N` available saved jobs before starting any run. Preserve inactive, insecure, or protocol-declared manual-only members with their static exclusion reason; do not replenish, replace, rescore, or expand the batch. If fewer than `N` saved jobs exist, report the frozen count rather than searching for substitutes.
|
|
48
48
|
- For each fixed batch member, preserve an explicit job ID -> application run ID -> browser tab mapping. Complete the full start -> conditional resume preparation/confirmation/verification when an upload control exists -> form completion -> `review_ready` lifecycle for every member. A review-ready run does not block the next member. Never submit any of them.
|
|
49
49
|
6. Call `trackly_start_apply_run` for the selected job or current fixed batch member with the complete `batchId`, `memberId`, `expectedMemberVersion`, `expectedInspectionEpoch`, and `leaseToken` returned by Trackly. This call is also the sanctioned idempotent lookup when a recovered member has no `runId`; call it with the exact recovered binding and Trackly will reuse the bound active run. Never create a replacement run because browser control was interrupted.
|
|
50
|
-
-
|
|
50
|
+
- If a bound start returns a transport failure, a non-access HTTP 5xx response, or an error explicitly marked `retryable: true`, preserve the frozen member and browser state. Refetch the active batch, renew its lease, and retry the same complete binding once. Classify the retry response independently with these same rules: route canonical `maintenance_mode` or legacy `planned_maintenance` directly through **Resume after maintenance**; surface controlled-access/request errors marked `retryable: false` and every other HTTP 4xx response unchanged; only a second transport failure, non-access HTTP 5xx response, or explicitly retryable error becomes `backend_run_start_unavailable`. Route maintenance on either attempt without consuming or relabeling the retry, and never relabel a permanent retry response as an outage. For `backend_run_start_unavailable`, continue other members and report a Trackly control-plane failure. Do not call `trackly_checkpoint_apply_batch` for this condition because start failure has not produced the required run ID. The unchanged frozen member is the durable resume point. Never switch that frozen member to an unbound legacy run or blame the employer form.
|
|
51
|
+
- Require `run.protocolVersion` to be 3.1.0 or newer and to share protocol major 3 with the fetched protocol. A new batch member requires 3.3.1 or newer; an explicit 3.2 single run may start or finish through its legacy path. Never continue a pre-evidence 3.0.x run under skill 4.2.3. Preserve that run instead of starting a replacement, record it `blocked` with a value-free protocol-upgrade reason when possible, and tell the user the saved job can be retried only after the stale run is cleared through Trackly's supported lifecycle. Stop and refetch the protocol and active batch if support level, execution mode, provider, required scenarios, authorized origin policy, member version, or inspection epoch changes after run creation.
|
|
51
52
|
- In guided mode, inspect the page before preparing any resume bytes. Confirm the employer, role, HTTPS origin, reachable review path, semantic controls, whether an attachment control exists, and absence of a credential, verification, CAPTCHA, or submit-only wall. A missing file input is not itself a blocker; skip the resume path when the application has no attachment control. Any other failed precondition is an execution blocker, not permission to improvise.
|
|
52
53
|
7. Pass the browser readiness gate before preparing resume bytes:
|
|
53
54
|
- Use semantic browser control through Codex in-app browser controls, Chrome MCP/extension browser control, or Claude in Chrome.
|
|
@@ -91,7 +92,7 @@ Follow this order:
|
|
|
91
92
|
4. Fill typed fields from the resolved Trackly profile. Clear parser-filled data when the canonical state is intentionally blank.
|
|
92
93
|
5. Use real UI clicks for React/native selects, radios, and checkboxes. Resolve boolean values by their exact semantic label (`true` to Yes, `false` to No), never by option order, index, proximity, or a stale prior selection. After every selection, compare the committed value with the canonical Trackly value. If the field is required or had a validation error before selection, verify that the required-field error disappeared. An optional control with no validation error passes when its committed value is correct. Treat any value mismatch or applicable stale error as a failed field and correct it before continuing.
|
|
93
94
|
6. Recheck email and phone through both browser DOM state and macOS accessibility state. Require exact values and reject duplicate/concatenated values.
|
|
94
|
-
7. Complete known optional fields, education, links, relocation, and source
|
|
95
|
+
7. Complete every visible field whose canonical answer is known, including optional fields, previous-employer/title history, education rows and dates, links, relocation, communication preferences, and opportunity source. Before review, compare the live field inventory with the resolved Trackly profile and prove that no known visible answer was silently omitted. Group only genuinely unknown contextual fields into the question packet.
|
|
95
96
|
- Treat partial dates as unknown at the missing precision. If Trackly has only a year but the ATS requires a month, ask once and sync the complete date before selecting either control. Never accept an ATS-selected current/default month or infer an education month.
|
|
96
97
|
8. Use the canonical `consent.background_check_if_advanced` field only when the form explicitly asks for consent to a background check if the candidate advances. If it is unknown, ask before selecting it and save the answer at the user's chosen scope. Never infer it from privacy, demographic, recruiting-data, general application, criminal-record, or professional-reference consent. Treat the latter two as separate unknown consent questions unless the current profile schema supplies their own canonical fields.
|
|
97
98
|
9. For a free-text application response, read [references/application-writing.md](references/application-writing.md). Calibrate from the user's Trackly writing fields, use only supported profile and role facts, and run the built-in voice and anti-slop gate before entering the response. Do not require a separate writing or humanizer skill.
|
|
@@ -111,12 +112,13 @@ Every required scenario and both universal evidence scenarios must have correspo
|
|
|
111
112
|
|
|
112
113
|
## Review handoff
|
|
113
114
|
|
|
114
|
-
After every conditional field is settled and all other review gates pass, bulk checkpoint every ready member with `review/manual_submit`, the current unchanged inspection epoch in both epoch fields, and any `resolvedActionIds`. Use the returned member versions and epochs; this checkpoint resolves the listed human actions and moves the durable member lifecycle to `review_ready` without invalidating current-epoch browser evidence or an unchanged resume-content approval. Do not wait for `needs_input` members: whenever at least one member is durably `review_ready`, ask for one explicit final truthfulness confirmation for the exact complete subset that is currently `review_ready`. If any form in that certified subset used a resume attachment, certify with `resumeDependency: approved` and the exact approved resume identity. If no form in the subset exposes a resume control, certify with `resumeDependency: not_applicable` and omit the resume ID and hash; do not invent an upload requirement. Then call `trackly_record_application_outcomes` once with every member in that certified subset using its exact current `runId`, `batchId`, `memberId`, `inspectionEpoch`, and `leaseToken`; refresh
|
|
115
|
+
After every conditional field is settled and all other review gates pass, bulk checkpoint every ready member with `review/manual_submit`, the current unchanged inspection epoch in both epoch fields, and any `resolvedActionIds`. Use the returned member versions and epochs; this checkpoint resolves the listed human actions and moves the durable member lifecycle to `review_ready` without invalidating current-epoch browser evidence or an unchanged resume-content approval. Do not wait for `needs_input` members: whenever at least one member is durably `review_ready`, ask for one explicit final truthfulness confirmation for the exact complete subset that is currently `review_ready`. If any form in that certified subset used a resume attachment, certify with `resumeDependency: approved` and the exact approved resume identity. If no form in the subset exposes a resume control, certify with `resumeDependency: not_applicable` and omit the resume ID and hash; do not invent an upload requirement. Then call `trackly_record_application_outcomes` once with every member in that certified subset using its exact current `runId`, `batchId`, `memberId`, `inspectionEpoch`, and `leaseToken`; every item must use the literal `outcome: review_ready`. Verify every recorded run returns `awaiting_manual_submit` before showing the review handoff. A member conflict does not invalidate successful siblings: preserve its tab, refresh that member once, and surface the returned stable conflict code instead of blindly replaying a different transition. A member that becomes ready later requires a fresh certification for the then-current complete `review_ready` subset; never reuse an older certification for it. Use singular `trackly_record_application_outcome` only for a legacy single run or an isolated post-review transition. Provide the review block defined in [references/review-handoff.md](references/review-handoff.md). For a single run, keep the browser on the final review state and stop. For a frozen batch, preserve every review-ready tab, hand off each certified review-ready subset without waiting on unrelated human actions, and continue the same lifecycle for the remaining mapped members. Members with unresolved actions stay frozen and resumable. Never submit any member. End with job ID -> run ID -> browser tab -> ATS -> status plus the actual scenario coverage for each run.
|
|
115
116
|
|
|
116
117
|
After the user submits manually:
|
|
117
118
|
|
|
118
|
-
- If a success page is visible, reclaim the current batch lease if needed, first record current-epoch `confirmation_detected` evidence with source `success_page` through `trackly_record_apply_submission_evidence`, then
|
|
119
|
-
- If the user explicitly confirms submission, reclaim the current batch lease if needed, first record current-epoch `confirmation_detected` evidence with source `user_confirmation` through `trackly_record_apply_submission_evidence`, then
|
|
119
|
+
- If a success page is visible, reclaim the current batch lease if needed, first record current-epoch `confirmation_detected` evidence with source `success_page` through `trackly_record_apply_submission_evidence`, then use the separate literal `outcome: submitted` with the exact current batch/member/epoch/lease binding and confirmation `success_page`.
|
|
120
|
+
- If the user explicitly confirms submission, reclaim the current batch lease if needed, first record current-epoch `confirmation_detected` evidence with source `user_confirmation` through `trackly_record_apply_submission_evidence`, then use the separate literal `outcome: submitted` with the exact current batch/member/epoch/lease binding and confirmation `user_confirmation`.
|
|
121
|
+
- Treat the outcome response as a durable commit gate. Refetch each submitted member and require both member lifecycle `submitted` and Trackly job state `applied_confirmed`. On conflict, preserve the success tab, refresh once, and replay only the documented idempotent evidence/outcome sequence. If reconciliation still fails, report a P0 reconciliation defect and leave the tab open; never claim Trackly moved the job.
|
|
120
122
|
- A provider receipt is optional orthogonal evidence. Record it as `provider_receipt_detected`; never use `provider_receipt` as the outcome confirmation or as a substitute for a success page or explicit user confirmation.
|
|
121
123
|
- If neither exists, do not move the job to applied.
|
|
122
124
|
- Treat a contradictory ATS response such as “already applied” as provisional until the exact requisition URL settles. Do not click Submit again. Preserve the page, confirm the job/requisition identifier is unchanged, and re-read the final route state after the UI and network activity settle. A later explicit success state on that same requisition overrides the provisional error and must be recorded as `submitted`; otherwise record the run as blocked without marking the job applied.
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
- Accept employer-hosted Greenhouse forms and `job-boards.greenhouse.io` / `boards.greenhouse.io` application hosts after matching the employer and role.
|
|
6
6
|
- Expect resume parsing, React selects, correction banners, demographic sections, and final consent checkboxes.
|
|
7
|
+
- Use the visible file chooser or its semantic file input; never click a nearby decorative upload region by coordinates.
|
|
8
|
+
- For custom selects and checkbox groups, verify the selected label or checked element in the live DOM after the real click. A displayed answer with a remaining required error is uncommitted.
|
|
7
9
|
- Treat red required-field text as authoritative even when a value is visible.
|
|
8
10
|
- A Greenhouse “Thank you for applying” page is a valid submission signal.
|
|
9
11
|
|
|
@@ -11,6 +13,9 @@
|
|
|
11
13
|
|
|
12
14
|
- Accept `jobs.ashbyhq.com` only after matching the employer and role.
|
|
13
15
|
- Expect rerenders, masked contact inputs, and controls whose visible text can differ from committed state.
|
|
16
|
+
- Resolve binary button groups by the live selected/active state and semantic Yes/No label, never by button order or styling alone.
|
|
17
|
+
- Treat education as repeatable structured rows. After activating `+ Add Education`, require the row count to increase before filling the new row. If Playwright reports a click but the submit-typed control does not add a row, retry with the visible semantic DOM control; stop if the row remains absent.
|
|
18
|
+
- Select localized school suggestions by the exact intended institution and then verify the committed row value.
|
|
14
19
|
- Best effort: stop when browser and accessibility state disagree.
|
|
15
20
|
- An explicit application-success banner/page is a valid submission signal.
|
|
16
21
|
|
|
@@ -37,6 +42,7 @@ This group includes SmartRecruiters, Workable, BambooHR, Recruitee, Jobvite, Tea
|
|
|
37
42
|
- Expect a mixture of native controls, custom widgets, employer subdomains, embedded frames, shared profile data, and optional resume parsing.
|
|
38
43
|
- Match the live HTTPS origin, employer, role, and requisition before entering private data.
|
|
39
44
|
- Use the same committed-state and required-error gate as Greenhouse. Familiar-looking controls do not lower the evidence requirement.
|
|
45
|
+
- On HiBob, treat document upload as a two-step commit when the UI requires choosing the file and then confirming the upload. Verify the final filename/attachment state; a selected local file alone is not an attached resume.
|
|
40
46
|
|
|
41
47
|
## Unknown employer-hosted form
|
|
42
48
|
|
|
@@ -38,10 +38,22 @@ For every protocol 3.3.1 request:
|
|
|
38
38
|
|
|
39
39
|
Do not recreate a batch after maintenance. Refetch the existing batch, reclaim
|
|
40
40
|
its lease with the latest revision, and resume its existing run bindings.
|
|
41
|
+
When a bound run start returns a transport failure, a non-access HTTP 5xx
|
|
42
|
+
response, or an error explicitly marked `retryable: true`, refetch and renew,
|
|
43
|
+
then retry the same complete binding once. Classify the retry response
|
|
44
|
+
independently with the same rules. Route `maintenance_mode` or the legacy
|
|
45
|
+
`planned_maintenance` alias from either attempt through maintenance recovery.
|
|
46
|
+
Surface controlled-access/request errors marked `retryable: false` and every
|
|
47
|
+
other HTTP 4xx response unchanged, including when returned by the retry. Only a
|
|
48
|
+
second transport failure, non-access HTTP 5xx response, or explicitly
|
|
49
|
+
retryable error becomes `backend_run_start_unavailable` while siblings
|
|
50
|
+
continue. Do not checkpoint this condition: no run ID exists yet, and the
|
|
51
|
+
checkpoint contract requires one. The unchanged frozen member is the durable
|
|
52
|
+
resume point. Never detach that member into a legacy single run.
|
|
41
53
|
|
|
42
54
|
### Request budget
|
|
43
55
|
|
|
44
|
-
For a new 20-member batch, keep
|
|
56
|
+
For a failure-free new 20-member batch, keep planning, initial binding, evidence,
|
|
45
57
|
two bulk checkpoints, resume approval, truth certification, outcomes, and the
|
|
46
58
|
final batch refresh within 52 non-resume MCP/HTTP requests: one active-batch
|
|
47
59
|
lookup, one create, one page, one claim, 20 run starts, 20 surface bindings, one
|
|
@@ -51,7 +63,12 @@ resume approval, one truth certification, one
|
|
|
51
63
|
`trackly_record_application_outcomes` call, and one final refresh. An existing
|
|
52
64
|
active batch omits the create call. Do not replace bulk observations,
|
|
53
65
|
checkpoints, or outcomes with per-member requests. Resume download and exact
|
|
54
|
-
local verification are excluded from this count.
|
|
66
|
+
local verification are excluded from this count. Each member that encounters
|
|
67
|
+
the one permitted retryable bound-start failure receives exactly three
|
|
68
|
+
additional recovery calls: refetch the active batch, renew its lease, and retry
|
|
69
|
+
the same binding. Therefore the bounded contingency budget is `52 + (3 * R)`,
|
|
70
|
+
where `R` is the number of affected members and cannot exceed 20. Maintenance
|
|
71
|
+
recovery is paced by the advertised window and is tracked separately.
|
|
55
72
|
|
|
56
73
|
## Ownership and replay safety
|
|
57
74
|
|
|
@@ -156,11 +173,14 @@ After all conditional questions and certification wording are visible, show one
|
|
|
156
173
|
final truthfulness prompt. Only after explicit user confirmation, compute the
|
|
157
174
|
value-free answer-snapshot and wording fingerprints and call
|
|
158
175
|
`trackly_certify_apply_batch_truth` for the exact complete subset that is
|
|
159
|
-
currently `review_ready`.
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
176
|
+
currently `review_ready`. Then call `trackly_record_application_outcomes` for
|
|
177
|
+
that certified subset; every item must use the literal
|
|
178
|
+
`outcome: review_ready`. Verify every recorded run returns
|
|
179
|
+
`awaiting_manual_submit` before handing the forms to the user. A `needs_input`
|
|
180
|
+
member does not block certification or handoff of ready siblings. Never certify
|
|
181
|
+
an arbitrary subset. When another member becomes ready later, obtain a fresh
|
|
182
|
+
certification for the then-current complete `review_ready` subset. Never place
|
|
183
|
+
the certification or its wording in the application profile.
|
|
164
184
|
|
|
165
185
|
A membership, profile revision, resume identity or hash, answer snapshot,
|
|
166
186
|
certification wording, or affected inspection epoch change invalidates the
|
|
@@ -182,6 +202,11 @@ Never submit a member. After manual submission, mark Applied only from an
|
|
|
182
202
|
observable success page or explicit user confirmation. Record the submit
|
|
183
203
|
request, success page or `user_confirmation`, and any provider receipt with
|
|
184
204
|
`trackly_record_apply_submission_evidence`; store only the redacted fingerprint
|
|
185
|
-
and typed source. Then
|
|
186
|
-
|
|
187
|
-
|
|
205
|
+
and typed source. Then use the separate literal `outcome: submitted`. The
|
|
206
|
+
outcome call is not complete until a fresh batch read shows member lifecycle
|
|
207
|
+
`submitted` and tracker state `applied_confirmed`.
|
|
208
|
+
Preserve the success tab during one documented idempotent conflict recovery;
|
|
209
|
+
if reconciliation remains unsuccessful, report the control-plane defect and
|
|
210
|
+
do not claim completion. Only then reconcile tab closure separately using the
|
|
211
|
+
browser-lifecycle gate. Submission, durable outcome, receipt, and closure never
|
|
212
|
+
substitute for one another.
|
|
@@ -43,6 +43,14 @@ Never make a closure claim from one inventory surface.
|
|
|
43
43
|
|
|
44
44
|
## Close proof
|
|
45
45
|
|
|
46
|
+
For a submitted application, do not begin tab closure until Trackly has
|
|
47
|
+
durably reconciled both the batch member to `submitted` and the saved job to
|
|
48
|
+
`applied_confirmed`. A success page or explicit user confirmation authorizes
|
|
49
|
+
the outcome write; it does not prove that the write committed. On a conflict,
|
|
50
|
+
keep the tab visible while the agent refreshes and performs the one documented
|
|
51
|
+
idempotent replay. If reconciliation still fails, leave the tab open and
|
|
52
|
+
report a control-plane defect.
|
|
53
|
+
|
|
46
54
|
`closed_verified` requires all of the following for the current inspection
|
|
47
55
|
epoch:
|
|
48
56
|
|