Skip to content

Commit acfb34e

Browse files
fix: adjustments on agentic check construct in prep for self-service billing rollout (#1293)
* fix: adjustments on agentic check construct in prep for self-service billing rollout * fix: remove agentic env exposure from CLI
1 parent c33b931 commit acfb34e

17 files changed

Lines changed: 108 additions & 389 deletions

File tree

examples/boilerplate-project-js/__checks__/agentic.check.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ new AgenticCheck('checkly-pricing-page', {
88
name: 'Checkly pricing page',
99
prompt:
1010
'Navigate to https://www.checklyhq.com/pricing and verify that at least three plan tiers are displayed on the page.',
11-
// Agentic checks currently run from a single location and follow their own
12-
// frequency cadence (30, 60, 120, 180, 360, 720 or 1440 minutes). The
13-
// construct hardcodes the location and validates the frequency for you.
14-
frequency: 60,
11+
// The backend enforces the allowed cadence and region count for your account.
12+
frequency: 5,
13+
locations: ['us-east-1', 'eu-west-1', 'ap-southeast-1'],
1514
})

examples/boilerplate-project/__checks__/agentic.check.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ new AgenticCheck('checkly-pricing-page', {
88
name: 'Checkly pricing page',
99
prompt:
1010
'Navigate to https://www.checklyhq.com/pricing and verify that at least three plan tiers are displayed on the page.',
11-
// Agentic checks currently run from a single location and follow their own
12-
// frequency cadence (30, 60, 120, 180, 360, 720 or 1440 minutes). The
13-
// construct hardcodes the location and validates the frequency for you.
14-
frequency: 60,
11+
// The backend enforces the allowed cadence and region count for your account.
12+
frequency: 5,
13+
locations: ['us-east-1', 'eu-west-1', 'ap-southeast-1'],
1514
})

packages/cli/e2e/__tests__/deploy.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ describe('deploy', { timeout: 45_000 }, () => {
314314

315315
expect(pricingCheck).toBeDefined()
316316
expect(pricingCheck.checkType).toEqual('AGENTIC')
317-
// The construct hardcodes a single location for agentic checks.
317+
// The construct keeps a us-east-1 fallback when no location is configured.
318318
expect(pricingCheck.locations).toEqual(['us-east-1'])
319319
expect(pricingCheck.tags).toEqual(expect.arrayContaining(['e2e', 'agentic']))
320320

packages/cli/e2e/__tests__/fixtures/deploy-agentic-project/agentic.check.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,5 @@ new AgenticCheck('agentic-runtime-check', {
2020
frequency: 60,
2121
agentRuntime: {
2222
skills: ['addyosmani/web-quality-skills'],
23-
exposeEnvironmentVariables: [
24-
'ENVIRONMENT_URL',
25-
{ name: 'TEST_USER_EMAIL', description: 'Login email for the test account' },
26-
],
2723
},
2824
})

packages/cli/src/ai-context/context.fixtures.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -834,13 +834,15 @@
834834
"id": "dddddddd-dddd-dddd-dddd-dddddddddddd",
835835
"checkType": "AGENTIC",
836836
"name": "Example Agentic Check",
837-
"frequency": 60,
837+
"frequency": 5,
838838
"frequencyOffset": 0,
839839
"activated": true,
840840
"muted": false,
841841
"shouldFail": false,
842842
"locations": [
843-
"us-east-1"
843+
"us-east-1",
844+
"eu-west-1",
845+
"ap-southeast-1"
844846
],
845847
"accountId": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
846848
"created_at": "2025-10-28T17:25:17.037Z",
@@ -874,7 +876,6 @@
874876
"prompt": "Navigate to https://www.checklyhq.com/pricing and verify that at least three plan tiers are displayed on the page.",
875877
"agenticCheckData": {
876878
"skills": [],
877-
"selectedEnvironmentVariables": [],
878879
"assertionRules": []
879880
},
880881
"alertChannelSubscriptions": [],

packages/cli/src/ai-context/references/configure-agentic-checks.md

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44
- Agentic checks are AI-powered: instead of writing code, you describe what the check should do in natural language with the `prompt` property. The agent decides how to satisfy the prompt at runtime.
55
- Write prompts as concrete imperative steps, not vague goals. Tell the agent which URL to navigate to and what specific signals confirm success — for example, "Navigate to https://example.com/pricing and verify that at least three plan tiers are displayed", not "Check that pricing works".
66
- Keep prompts under 10000 characters. The construct will fail validation otherwise.
7-
- **Frequency is restricted.** Only `30`, `60`, `120`, `180`, `360`, `720`, or `1440` minutes are accepted (matching `Frequency.EVERY_30M`, `EVERY_1H`, `EVERY_2H`, `EVERY_3H`, `EVERY_6H`, `EVERY_12H`, `EVERY_24H`). Anything else fails validation.
8-
- **Locations are not configurable.** Agentic checks currently run from a single fixed location. The construct hardcodes it — do not pass `locations` or `privateLocations`.
7+
- **Frequency is entitlement-gated by the backend.** You can configure the same `frequency` values as other checks, including `Frequency.EVERY_5M` / `5`. The backend enforces the fastest cadence available to the account.
8+
- **Locations are entitlement-gated by the backend.** You can pass `locations` just like other public checks. The backend enforces the allowed number of regions for the account. `privateLocations` are not supported.
99
- **Several common check fields are intentionally omitted** from `AgenticCheckProps`: `runParallel`, `retryStrategy`, `shouldFail`, `doubleCheck`, `triggerIncident`, and `groupId`. The platform does not yet honor these for agentic checks. Setting them in the construct is a TypeScript error.
1010
- **Important:** The target URL must be publicly accessible. Checks run on Checkly's cloud infrastructure, not locally. If the user is developing against localhost, suggest a tunneling tool (ngrok, cloudflare tunnel) or a preview/staging deployment.
1111
- **Plan-gated:** Agentic checks require the `AGENTIC_CHECKS` entitlement on the account. Run `npx checkly skills manage` to check entitlements before using.
1212

13-
## `agentRuntime` — security boundary for skills and env vars
13+
## `agentRuntime` skills
1414

15-
`agentRuntime` is the explicit allowlist of resources the agent may use at execution time. Anything not declared in `agentRuntime` is **unavailable** to the agent. Treat it as a security boundary: the smaller the runtime surface, the smaller the blast radius of any prompt injection.
15+
`agentRuntime` is used to add skills the agent may use at execution time.
1616

1717
```typescript
1818
agentRuntime: {
@@ -25,23 +25,10 @@ agentRuntime: {
2525
// - owner/repo form: 'addyosmani/web-quality-skills'
2626
// - plain name: 'cost-optimization'
2727
skills: ['addyosmani/web-quality-skills'],
28-
29-
// Environment variables the agent is allowed to read at runtime.
30-
// Anything not listed here is hidden from the agent process — even
31-
// if it's defined at the project or check level.
32-
exposeEnvironmentVariables: [
33-
// Bare string form: variable name only.
34-
'ENVIRONMENT_URL',
35-
// Object form: pair the variable with a description so the agent
36-
// can decide when to read it. Descriptions are passed to the model
37-
// and are truncated to 200 characters.
38-
{ name: 'TEST_USER_EMAIL', description: 'Login email for the test account' },
39-
],
4028
},
4129
```
4230

43-
- Only declare env vars the agent **needs**. Adding a variable to `exposeEnvironmentVariables` exposes it to the model and to anything the model invokes via skills.
44-
- Descriptions are not just documentation — they steer the model's decisions. Use them to disambiguate variables that have non-obvious names.
31+
- Reference Checkly environment variables directly in the prompt with double brackets, for example `{{ENVIRONMENT_URL}}`.
4532
- The runner installs each skill via `npx skills add` at the start of every check run. The CLI does not validate the skill identifier at deploy time, so a typo will not surface until the first run.
4633
- The `playwright-cli` skill is preloaded for every agentic check. Only declare additional skills here.
4734

packages/cli/src/constructs/__tests__/agentic-check-codegen.spec.ts

Lines changed: 6 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,14 @@ describe('AgenticCheckCodegen', () => {
8888
expect(source).toContain('prompt: \'Verify the homepage loads.\'')
8989
})
9090

91-
it('should not emit `locations` even when the backend returns one', async () => {
92-
// The backend forces a single location for agentic checks today and
93-
// the construct hardcodes it. Surfacing it in generated code would
94-
// break type-checking against `AgenticCheckProps`.
91+
it('should emit `locations` when the backend returns them', async () => {
9592
const source = await renderResource(env, baseResource({
96-
locations: ['us-east-1'],
93+
locations: ['us-east-1', 'eu-west-1'],
9794
}))
9895

99-
expect(source).not.toContain('locations')
96+
expect(source).toContain('locations: [')
97+
expect(source).toContain('\'us-east-1\'')
98+
expect(source).toContain('\'eu-west-1\'')
10099
})
101100

102101
it('should not emit `retryStrategy`', async () => {
@@ -127,11 +126,10 @@ describe('AgenticCheckCodegen', () => {
127126
expect(source).not.toContain('agentRuntime')
128127
})
129128

130-
it('should not emit `agentRuntime` when skills and env vars are both empty', async () => {
129+
it('should not emit `agentRuntime` when skills are empty', async () => {
131130
const source = await renderResource(env, baseResource({
132131
agenticCheckData: {
133132
skills: [],
134-
selectedEnvironmentVariables: [],
135133
},
136134
}))
137135
expect(source).not.toContain('agentRuntime')
@@ -148,8 +146,6 @@ describe('AgenticCheckCodegen', () => {
148146
expect(source).toContain('skills: [')
149147
expect(source).toContain('\'addyosmani/web-quality-skills\'')
150148
expect(source).toContain('\'cost-optimization\'')
151-
// No empty exposeEnvironmentVariables when none are selected.
152-
expect(source).not.toContain('exposeEnvironmentVariables')
153149
})
154150

155151
it('should drop empty skill names', async () => {
@@ -165,67 +161,6 @@ describe('AgenticCheckCodegen', () => {
165161
expect(source).not.toMatch(/skills:\s*\[[^\]]*''/m)
166162
})
167163

168-
it('should emit `agentRuntime.exposeEnvironmentVariables` for bare-string entries', async () => {
169-
const source = await renderResource(env, baseResource({
170-
agenticCheckData: {
171-
selectedEnvironmentVariables: ['ENVIRONMENT_URL', 'API_KEY'],
172-
},
173-
}))
174-
175-
expect(source).toContain('exposeEnvironmentVariables: [')
176-
expect(source).toContain('\'ENVIRONMENT_URL\'')
177-
expect(source).toContain('\'API_KEY\'')
178-
// Bare strings should not be expanded into objects. The only `name:`
179-
// we expect in the file is the top-level `name: 'Agentic Check'`.
180-
expect((source.match(/name:/g) ?? []).length).toEqual(1)
181-
})
182-
183-
it('should reverse-translate `key` into `name` for object-form entries', async () => {
184-
// The backend stores selected env vars as `{ key, description? }` but
185-
// the construct exposes `{ name, description? }`. The codegen has to
186-
// translate on the way out so the generated file matches the construct
187-
// type.
188-
const source = await renderResource(env, baseResource({
189-
agenticCheckData: {
190-
selectedEnvironmentVariables: [
191-
{ key: 'TEST_USER_EMAIL', description: 'Login email for the test account' },
192-
],
193-
},
194-
}))
195-
196-
expect(source).toContain('name: \'TEST_USER_EMAIL\'')
197-
expect(source).toContain('description: \'Login email for the test account\'')
198-
expect(source).not.toContain('key:')
199-
})
200-
201-
it('should omit `description` when not provided on object-form entries', async () => {
202-
const source = await renderResource(env, baseResource({
203-
agenticCheckData: {
204-
selectedEnvironmentVariables: [
205-
{ key: 'PLAIN_KEY' },
206-
],
207-
},
208-
}))
209-
210-
expect(source).toContain('name: \'PLAIN_KEY\'')
211-
expect(source).not.toContain('description')
212-
})
213-
214-
it('should support a mix of bare-string and object-form env vars', async () => {
215-
const source = await renderResource(env, baseResource({
216-
agenticCheckData: {
217-
selectedEnvironmentVariables: [
218-
'ENVIRONMENT_URL',
219-
{ key: 'TEST_USER_EMAIL', description: 'Login email' },
220-
],
221-
},
222-
}))
223-
224-
expect(source).toContain('\'ENVIRONMENT_URL\'')
225-
expect(source).toContain('name: \'TEST_USER_EMAIL\'')
226-
expect(source).toContain('description: \'Login email\'')
227-
})
228-
229164
it('should never emit `assertionRules`', async () => {
230165
// Assertion rules are agent-generated and preserved server-side. The
231166
// construct does not accept them, so generated code must not surface

packages/cli/src/constructs/__tests__/agentic-check.spec.ts

Lines changed: 44 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ describe('AgenticCheck', () => {
6969
runParallel: false,
7070
agentRuntime: {
7171
skills: [],
72-
exposeEnvironmentVariables: [],
7372
},
7473
}),
7574
}),
@@ -78,7 +77,7 @@ describe('AgenticCheck', () => {
7877
}))
7978
}, DEFAULT_TEST_TIMEOUT)
8079

81-
it('should expose agentRuntime skills and environment variables', async () => {
80+
it('should expose agentRuntime skills', async () => {
8281
const output = await parseProject(
8382
fixt,
8483
'--config',
@@ -99,10 +98,6 @@ describe('AgenticCheck', () => {
9998
checkType: 'AGENTIC',
10099
agentRuntime: {
101100
skills: ['addyosmani/web-quality-skills'],
102-
exposeEnvironmentVariables: [
103-
'API_KEY',
104-
{ name: 'TEST_USER_PASSWORD', description: 'Login password for the test account' },
105-
],
106101
},
107102
}),
108103
}),
@@ -114,7 +109,6 @@ describe('AgenticCheck', () => {
114109
checkType: 'AGENTIC',
115110
agentRuntime: {
116111
skills: [],
117-
exposeEnvironmentVariables: [],
118112
},
119113
}),
120114
}),
@@ -123,7 +117,7 @@ describe('AgenticCheck', () => {
123117
}))
124118
}, DEFAULT_TEST_TIMEOUT)
125119

126-
it('should default to a single us-east-1 location and ignore project-level locations', async () => {
120+
it('should apply project-level locations', async () => {
127121
const output = await parseProject(
128122
fixt,
129123
'--config',
@@ -142,7 +136,36 @@ describe('AgenticCheck', () => {
142136
member: true,
143137
payload: expect.objectContaining({
144138
checkType: 'AGENTIC',
145-
locations: ['us-east-1'],
139+
locations: ['eu-west-1', 'ap-southeast-1'],
140+
frequency: 30,
141+
runParallel: false,
142+
}),
143+
}),
144+
]),
145+
}),
146+
}))
147+
}, DEFAULT_TEST_TIMEOUT)
148+
149+
it('should apply check-level locations', async () => {
150+
const output = await parseProject(
151+
fixt,
152+
'--config',
153+
fixt.abspath('test-cases/test-locations-explicit/checkly.config.js'),
154+
)
155+
156+
expect(output).toEqual(expect.objectContaining({
157+
diagnostics: expect.objectContaining({
158+
fatal: false,
159+
}),
160+
payload: expect.objectContaining({
161+
resources: expect.arrayContaining([
162+
expect.objectContaining({
163+
logicalId: 'locations-explicit',
164+
type: 'check',
165+
member: true,
166+
payload: expect.objectContaining({
167+
checkType: 'AGENTIC',
168+
locations: ['us-east-1', 'eu-west-1', 'ap-southeast-1'],
146169
frequency: 30,
147170
runParallel: false,
148171
}),
@@ -257,7 +280,7 @@ describe('AgenticCheck', () => {
257280
}))
258281
}, DEFAULT_TEST_TIMEOUT)
259282

260-
it('should fail validation when frequency is not in the supported set', async () => {
283+
it('should allow faster frequencies so the backend can enforce account entitlements', async () => {
261284
const output = await parseProject(
262285
fixt,
263286
'--config',
@@ -266,48 +289,19 @@ describe('AgenticCheck', () => {
266289

267290
expect(output).toEqual(expect.objectContaining({
268291
diagnostics: expect.objectContaining({
269-
fatal: true,
270-
observations: expect.arrayContaining([
271-
expect.objectContaining({
272-
message: expect.stringContaining('"frequency" must be one of 30, 60, 120, 180, 360, 720, 1440'),
273-
}),
274-
]),
275-
}),
276-
}))
277-
}, DEFAULT_TEST_TIMEOUT)
278-
279-
it('should fail validation when an environment variable name is empty', async () => {
280-
const output = await parseProject(
281-
fixt,
282-
'--config',
283-
fixt.abspath('test-cases/test-validation-empty-env-var-name/checkly.config.js'),
284-
)
285-
286-
expect(output).toEqual(expect.objectContaining({
287-
diagnostics: expect.objectContaining({
288-
fatal: true,
289-
observations: expect.arrayContaining([
290-
expect.objectContaining({
291-
message: expect.stringContaining('"agentRuntime.exposeEnvironmentVariables[0]" must have a non-empty name'),
292-
}),
293-
]),
292+
fatal: false,
294293
}),
295-
}))
296-
}, DEFAULT_TEST_TIMEOUT)
297-
298-
it('should fail validation when an environment variable description exceeds 200 characters', async () => {
299-
const output = await parseProject(
300-
fixt,
301-
'--config',
302-
fixt.abspath('test-cases/test-validation-description-too-long/checkly.config.js'),
303-
)
304-
305-
expect(output).toEqual(expect.objectContaining({
306-
diagnostics: expect.objectContaining({
307-
fatal: true,
308-
observations: expect.arrayContaining([
294+
payload: expect.objectContaining({
295+
resources: expect.arrayContaining([
309296
expect.objectContaining({
310-
message: expect.stringContaining('"agentRuntime.exposeEnvironmentVariables[0].description" must be at most 200 characters'),
297+
logicalId: 'low-frequency',
298+
type: 'check',
299+
member: true,
300+
payload: expect.objectContaining({
301+
checkType: 'AGENTIC',
302+
frequency: 5,
303+
locations: ['us-east-1'],
304+
}),
311305
}),
312306
]),
313307
}),

packages/cli/src/constructs/__tests__/fixtures/agentic-check/test-cases/test-agent-runtime/test.check.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,6 @@ new AgenticCheck('agent-runtime-check', {
55
prompt: 'Sign in to the test account and verify the dashboard loads.',
66
agentRuntime: {
77
skills: ['addyosmani/web-quality-skills'],
8-
exposeEnvironmentVariables: [
9-
'API_KEY',
10-
{ name: 'TEST_USER_PASSWORD', description: 'Login password for the test account' },
11-
],
128
},
139
})
1410

packages/cli/src/constructs/__tests__/fixtures/agentic-check/test-cases/test-validation-description-too-long/checkly.config.js renamed to packages/cli/src/constructs/__tests__/fixtures/agentic-check/test-cases/test-locations-explicit/checkly.config.js

File renamed without changes.

0 commit comments

Comments
 (0)