GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — feat(site): add organization skill settings with a shared skills UI by ibetitsmike · Pull Request #30612 · coder/coder

Conversation

@ibetitsmike

@ibetitsmike ibetitsmike commented Oct 11, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Collaborator

Stack

Part of CODAGT-1341. This stack adds organization skills to Coder Agents: admins publish a skill once per organization, share it with groups or members, and chats in that organization load it next to personal and workspace skills. It replaces the 21-PR draft stack #30584 to #30604 with five PRs, bottom to top:

  1. feat: add the organization skills data model #30609 data model: one migration, queries, RBAC and dbauthz
  2. feat: add organization skill API routes #30610 organization skill API routes and the scope-neutral SDK
  3. feat: add organization skill sharing ACL routes #30611 sharing ACL routes
  4. feat(site): add organization skill settings with a shared skills UI #30612 settings UI: shared skills table, admin page, member section (this PR)
  5. feat: load organization skills in chats #30613 chats: chatd loading, / menu, docs

What changes

This PR turns the personal skills page into a skills table that works for any owner, then uses it for an organization admin page and a read-only member section. It changes only site/.

Shared skills table. The personal page's files move to owner-neutral paths (kept as git renames, so the diff shows edits): AgentSettingsPersonalSkillsPageView.tsx becomes components/SkillsTableView.tsx, AgentSettingsPersonalSkillsPage.tsx becomes components/SkillsTable.tsx, PersonalSkillEditor becomes SkillEditor, and utils/personalSkills becomes utils/skills. queries/userSkills.ts keeps main's query names and keys for personal skills, and the new queries/organizationSkills.ts holds the organization and ACL queries. The table takes a SkillsScope (list, detail, create, update and delete queries), built by userSkillsScope or organizationSkillsScope in utils/skills.ts, plus an access object (create, update, delete) and its copy as props.

  • Enabled toggle: SkillEnabledSwitch runs one update mutation per row from the table's scope, is disabled while it is pending, and invalidates the list when it settles, which also drops a skill deleted elsewhere.
  • Read-only status: a table without update access (the member section, and auditors on the admin page) shows a green check ("Enabled") or a gray cross ("Disabled") in the Enabled column instead of a disabled switch. Editable tables keep the switch.
  • Read-only view: when the caller can't update a skill, the row opens SkillEditor in read-only mode with a Close button, replacing the old View dialog. It omits the naming hint and starts focus on Close.
  • Dialogs return focus to the control that opened them (useDialogFocusReturn).
  • Create, update and delete invalidate the skill list instead of patching it by hand. Update also writes the PATCH response to the skill's detail, so a reopened editor shows the new content.
  • Saving an ACL refreshes the organization skill list and the skill's detail. Deleting a skill removes its detail and the ACL queries cached under it, so a skill recreated with the same name doesn't inherit them.

Admin page at /ai/settings/skills?org=<name> (AISettingsPage/SkillsPage): lists, creates, edits, toggles and deletes organization skills with the caller's per-organization permissions, and opens OrganizationSkillSharingDialog for users with share. A requested organization the caller can't read shows the permission error instead of falling back to another organization, so a skill is never added to an organization the URL didn't name. The new viewAnyOrganizationSkills permission adds Skills to the AI settings sidebar, shows the navbar's AI settings link, and lets the AI settings index redirect to the skills page. The sidebar's Skills link keeps the current ?org= only when the user can read that organization's skills, using the page's own filter (readableSkillsOrganizations), so following the link never lands on the permission error.

Member section. The agent settings page becomes /agents/settings/skills ("Skills" in the sidebar; the old /agents/settings/personal-skills URL redirects). Below personal skills, "From your organizations" shows one organization at a time, read-only. Its picker lists the organizations the user is a member of that have enabled skills for them (an organization still loading or whose list failed stays listed), starts on the default organization, and is hidden when only one organization qualifies. Export all downloads only the selected organization's skills. If the selected organization's list fails, a retry button (labeled "Retry loading name skills") replaces the table.

Shared sharing helpers. ChatModelPrincipalAutocomplete becomes components/ACLPrincipalAutocomplete, used by the model, MCP server and skill sharing dialogs; MCPServerPrincipalAutocomplete is deleted and the common ACL diff logic moves to aclSharing.ts. A new ChatModelSharingDialog.test.tsx guards the model dialog through the swap.

Declined on purpose (Mike's call): extra toggle cache hardening, namely a pending-toggle map, reconciling a View that 404s, and guarding a stale refetch against a retried toggle. Invalidating on settle already refetches the list after every toggle.

Commits

This PR reworks the old site layers rather than reproducing them. The commits go in review order: shared helpers, renames, the shared table, the two pages, then review fixes.

  1. 6463992b717 refactor: share the ACL principal autocomplete and sharing helpers.
  2. e18599f5049 refactor: move the personal skills files to shared skills paths (file moves plus import path updates only).
  3. 3c71e6c2168 refactor: drop the personal prefix from shared skill symbols.
  4. 3be35bcde68 refactor: key the skills table and queries by owner.
  5. d0c1dfcfdd1 fix: return focus to the opener when a skills dialog closes.
  6. 92ef6351eb4 feat: add an Enabled toggle to the skills table.
  7. 31c103e5396 refactor: move the skill edit and delete dialogs to their own file.
  8. cff0bef4576 feat: view a skill read-only when the user cannot edit it.
  9. a8b54a22981 feat: add the organization skills admin page with sharing.
  10. 391401b62b7 feat: show organization skills on the personal skills page.
  11. 2cf6e250a60 refactor: keep the skill dialogs in the table view and extract focus return. This undoes the file split from commit 7 so SkillsTableView.tsx still diffs as a rename (497 lines then, 507 at the head).
  12. 0af93452c7d test: keep only the role wiring test for the skills page.
  13. 8032c6708a8 fix: refetch the skill list after a create when no list is cached (superseded by item 22).
  14. a52f9ba659c refactor: tidy skills copy, editor prop naming, and story fixtures.
  15. f10bc316305 fix: refresh the organization skill list after saving its ACL. Saving an ACL bumps the skill's updated_at, so the save now also invalidates the organization skill list and the skill's detail; a new test in api/queries/skills.test.ts (now organizationSkills.test.ts) covers it.
  16. 698a6d0b55f Merge the updated sharing layer into settings-ui, bringing in feat: add organization skill API routes #30610's PATCH fix.
  17. aaa356f0fd5 fix: drop the editing hint and field focus from the read-only skill view. From the remote UAT: read-only View no longer shows the Name field's naming hint, and the dialog opens with focus on Close instead of a field (onOpenAutoFocus, like ChatSearchDialog). The new SkillEditor.test.tsx case "starts focus on Close when read-only" fails without the fix.
  18. 698dd83946d fix: drop a deleted skill's ACL caches with its detail. The delete now removes every query under the skill's key, not only the exact detail; a new case in api/queries/skills.test.ts (now organizationSkills.test.ts) covers it.
  19. f82573cd1c2 fix: carry only a skill-readable organization on the Skills link, with a table-driven AISettingsSidebar.test.tsx case.
  20. 0e55137de7b fix: share the skill-readable organization filter (SkillsPage/readableSkillsOrganizations.ts, used by the sidebar and SkillsPage) and cover an organization that is listed but unreadable.
  21. 97d42fd3cd8 refactor: split skill queries by owner. queries/skills.ts goes back to main's userSkills.ts (main's names and keys) plus a new organizationSkills.ts for the organization and ACL queries; the table takes a SkillsScope instead of an owner union.
  22. 4ddfb80ac54 refactor: invalidate skill lists after writes, instead of patching the cached list; update still writes the detail from the PATCH response.
  23. 14d5b755087 refactor: pass skill organizations to the sidebar as Organization objects instead of names.
  24. 463df6a5e69 feat: pick one organization on the member skills page.
  25. 9c802557b9c refactor: tighten the skill query comments and tests.
  26. 9002dc60382 test: cover the failed sharing save in Vitest (OrganizationSkillSharingDialog.test.tsx).
  27. a9df756b976 and 5ebf7b8984a merge the updated sharing layer, which brings in main. a9df756b976 moves the toast imports in OrganizationSkillSharingDialog.tsx and SkillEnabledSwitch.tsx to #/components/Toaster/toast, as main's Biome import rule now requires, and resolves conflicts with main in the model and MCP server sharing dialogs.
  28. ac3e62c83b7 test: assert the member page's organization switch through requests. After a switch, the test checks that the list and the viewed skill are requested from the selected organization (a Codex review finding).
  29. 63bb42754e3 fix: show read-only skill status instead of a disabled switch (from jaaydenh's review). SkillEnabledSwitch loses its disabled prop; a new ReadOnly story in SkillsTableView.stories.tsx shows the icons, and the read-only case in SkillsTable.test.tsx asserted the status icon and no switch (removed again in item 30).
  30. 82b2487ad17 test: address Codex review on skills tests. The SkillsPage.test.tsx update-only case now edits the description, saves, and asserts the updateOrganizationSkill call. The read-only status case in SkillsTable.test.tsx is removed because the ReadOnly story covers that visual state, and renderTable loses its access argument. AISettingsSidebar.test.tsx's hoisted permissions mock drops its cast for an explicit return type.
  31. 658be8b8df5 merges the updated sharing layer (main at e7b76872098); no changes of its own.

Size

Production +1465/-617, tests and stories +1104/-141 (tests +690 net, stories +273 net), generated +4/-0; total +2573/-758. The site changes in this PR and #30613 net +2263 lines, against +3058 for the same scope in the old stack. This is above the 500-line reviewer-friendly limit on purpose: Mike asked for 4 to 5 PRs instead of the 21 small ones this stack replaces.

Replaces

#30590 (site rename), #30595 (site API), #30596 (skills table), #30597 (Enabled toggle), #30598 (organization page), #30599 (ACL autocomplete), #30600 (permissions), #30603 (member page).

Validation

  • pnpm run lint clean (tsc, oxlint, knip, React Compiler) and Biome clean; pnpm run lint reran clean on 13f03d095ff, which contains this PR up to 0e55137de7b.
  • Vitest: 9 files, 49 tests. Storybook Vitest: 7 files, 101 tests. These full runs were on a52f9ba659c; on 0e55137de7b, the three test files the later fixes change (api/queries/skills.test.ts, AISettingsSidebar.test.tsx, SkillEditor.test.tsx) and the two SkillsPage tests that cover the changed SkillsPage.tsx pass, 20 tests.
  • On a6f8f63ad13, which contains this PR up to 5ebf7b8984a and both main merges: 38 Vitest files (the skill queries, the sidebar, the skill pages and components, the slash menu, and pages/AgentsPage/utils) pass, 542 tests with 2 skipped.
  • On 63bb42754e3: pnpm check and the full pnpm run lint pass; Vitest (SkillsTable, SkillsPage, AgentSettingsSkillsPage: 6 tests) and Storybook Vitest (the SkillsTableView, AgentSettingsSkillsPage and SkillsPage stories: 34 tests) pass; coder-frontend-review passed.
  • On 82b2487ad17: pnpm check, the full pnpm run lint, and Vitest on the three changed test files (7 tests) pass.
  • On 658be8b8df5: go build, pnpm check and the full pnpm lint pass; 6 Vitest files with 39 tests pass.
  • frontend-review (FE1 to FE10) and coder-frontend-review (8 reviewer roles); findings fixed or declined as noted above.
  • Remote UAT round 7 through Coder Agents passed on the whole stack, last on 13f03d095ff, which contains this PR up to 0e55137de7b; see feat: load organization skills in chats #30613's Validation for scope and findings.
  • Remote UAT round 8 passed on b03c14c86de (one item graded on intent; see feat: load organization skills in chats #30613), which contains this PR up to 9c802557b9c: the member page organization picker, list refresh after writes on the personal and admin tables, no stale ACL after deleting and recreating a skill, and the sidebar Skills ?org=. See feat: load organization skills in chats #30613 for details. 9002dc60382, ac3e62c83b7, 63bb42754e3, 82b2487ad17 and the main merges have tests but no UAT run.

Xum opened this PR on behalf of @ibetitsmike.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

chatgpt-codex-connector[bot] reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
ibetitsmike added 23 commits October 10, 2026 20:44
@ibetitsmike
feat: add the organization skills data model
baa3150
Rename user_skills to skills and add organization and project owners, an
enabled flag, and per-skill user and group ACL columns in one migration.
Add the organization_skill RBAC resource, scopes, audit table entry, skill
queries, and dbauthz methods. The personal skills API, SDK, and frontend
are unchanged.
@ibetitsmike
test(coderd/database): keep only the SQL paths of the org skill matrix
1b84e83
TestOrganizationSkillAuthorization becomes TestOrganizationSkillQueries.
Coverage showed it is the only PR 1 test that runs the SQL-filtered list
with rows (the regosql converter and the row scan of
GetAuthorizedOrganizationSkillMetadata) and the only one that executes
UpdateOrganizationSkillByOrganizationIDAndName and
DeleteOrganizationSkillByOrganizationIDAndName, so those stay.

Removed cases and what covers them:
- Member, OrgAuditor, OtherOrgMember list cases: same SQL predicates as
  GroupMember, GrantedMember, OrgAdmin and GrantedOutside.
- Single-row get checks: TestRolePermissions OrganizationSkill* and
  TestSkillRBACObjectOrganizationACL decide the same Rego rules, and the
  dbauthz method suite asserts the fetch authorizes read on the row.
- Read-grant write denials: TestRolePermissions
  OrganizationSkillUserACLWrite and TestSkillRBACObjectOrganizationACL.
@ibetitsmike
test(coderd/database): fold the skill cap cases into existing coverage
e2931b4
The user branch of enforce_skills_per_owner_limit is already covered by
TestUserSkillLimit and TestUserSkillLimitConcurrentCreates in coderd,
which assert the skills_per_user_limit mapping to 409. The organization
case repeated ConcurrentOrganizationInsertsHonorCap, so that test now
also proves disabled rows count toward the cap and that another
organization is unaffected. Only the project branch keeps its own case.
@ibetitsmike
test(coderd/rbac): drop the organization skill read scope test
be62aea
TestExternalScopeNames already expands every catalog entry, including
organization_skill:read, to its single site permission, and allowing a
site scope permission on an organization object is generic Authorize
behavior. The catalog entry itself is pinned by the generated
codersdk/apikey_scopes_gen.go: removing it changes the generator output.
@ibetitsmike
feat: add organization skill API routes
49cb2c8
Make the skill SDK types scope-neutral, return enabled on skill
responses, and accept PATCH {content?, enabled?} for personal and
organization skills. Add organization skill CRUD routes under
/api/experimental/organizations/{organization}/skills with a param
middleware and an audit wrapper type.

API contract change: skill responses gain enabled, and the update
request's content becomes optional.
@ibetitsmike
refactor(coderd): share the skill create and update path across owners
dc893bc
@ibetitsmike
test(coderd): merge duplicate personal and organization skill tests
f949254
@ibetitsmike
feat: add organization skill sharing ACL routes
b1c8556
Add per-skill user and group ACL queries and GET/PATCH
/api/experimental/organizations/{organization}/skills/{skill}/acl plus
GET .../acl/available. Extract the MCP server ACL helpers into
coderd/mcp_acl.go so both resources share validation. The PATCH locks
the granted users' organization memberships before the skill row, which
matches the member-removal trigger's lock order.
@ibetitsmike
test(coderd): merge duplicate organization skill ACL route tests
b5d2ee2
The ACL handlers share their validation, canonicalization and candidate
listing helpers in coderd/mcp_acl.go with MCP server configs, and
TestMCPServerConfigACL and TestMCPServerConfigACLAvailable already cover
every block of those helpers. Role coverage of the share action lives in
TestRolePermissions.

So the site owner sharer case, the org auditor non-sharer case, the
foreign user, foreign group and duplicate spelling rejections, and the
separate available-candidates subtest go. The org admin subtest now also
checks that a user from another organization is not a candidate, which
fails if the handler passes the wrong organization. The unsupported role
rejection, sparse updates with user and group grants, scoped API keys,
the concurrent delete, and the member removal lock order tests stay.
@ibetitsmike
refactor(site/src/pages/AISettingsPage): share the ACL principal auto…
6463992
…complete and sharing helpers
@ibetitsmike
refactor(site/src): move the personal skills files to shared skills p…
e18599f
…aths
@ibetitsmike
refactor(site/src/pages/AgentsPage): drop the personal prefix from sh…
3c71e6c
…ared skill symbols
@ibetitsmike
refactor(site/src): key the skills table and queries by owner
3be35bc
@ibetitsmike
fix(site/src/pages/AgentsPage/components): return focus to the opener…
d0c1dfc
… when a skills dialog closes
@ibetitsmike
feat(site/src/pages/AgentsPage/components): add an Enabled toggle to …
92ef635
…the skills table
@ibetitsmike
refactor(site/src/pages/AgentsPage/components): move the skill edit a…
31c103e
…nd delete dialogs to their own file
@ibetitsmike
feat(site/src/pages/AgentsPage/components): view a skill read-only wh…
cff0bef
…en the user cannot edit it
@ibetitsmike
feat(site): add the organization skills admin page with sharing
a8b54a2
@ibetitsmike
feat(site/src): show organization skills on the personal skills page
391401b
@ibetitsmike
refactor(site/src/pages/AgentsPage): keep the skill dialogs in the ta…
2cf6e25
…ble view and extract focus return
@ibetitsmike
test(site/src/pages/AISettingsPage/SkillsPage): keep only the role wi…
0af9345
…ring test for the skills page
@ibetitsmike
fix(site/src/api/queries): refetch the skill list after a create when…
8032c67
… no list is cached
@ibetitsmike
refactor(site/src): tidy skills copy, editor prop naming, and story f…
a52f9ba
…ixtures
@ibetitsmike
ibetitsmike added this pull request to stack #30614 October 11, 2026 00:29
@github-actions github-actions Bot assigned ibetitsmike Oct 11, 2026
@ibetitsmike

ibetitsmike commented Oct 11, 2026

Copy link
Copy Markdown
Collaborator Author

@codex review

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 11, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-13T15:35:15.026949Z 658be8b Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

chatgpt-codex-connector[bot]
chatgpt-codex-connector Bot reviewed Oct 11, 2026
View reviewed changes

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

coder/site/src/pages/AgentsPage/components/SkillsTableView.stories.tsx

Lines 150 to 152 in a52f9ba

expect(args.onDownload).toHaveBeenCalledWith(
expect.objectContaining({ name: "review-sql" }),
);

P2 Badge Move callback assertions out of Storybook play functions

This play function, along with the export, delete, and submit stories below, asserts callback behavior inside Storybook. FE1 reserves play for visual-state setup and requires meaningful callback assertions in Vitest; SkillsTable.test.tsx currently covers only toggling and focus return, so these interactions have no compliant behavior coverage and can instead fail Pixel before capture. Move the callback assertions into Vitest and leave only screenshot setup in the stories.

AGENTS.md reference: site/AGENTS.md:L7-L7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread site/src/pages/AgentsPage/AgentSettingsSkillsPage.tsx Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread site/src/api/queries/skills.ts Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread site/src/pages/AgentsPage/components/SkillEnabledSwitch.tsx Resolved

Uh oh!

There was an error while loading. Please reload this page.

This was referenced Oct 11, 2026
feat: add the organization skills data model #30609
Merged
feat: add organization skill API routes #30610
Merged
chatgpt-codex-connector[bot]
chatgpt-codex-connector Bot reviewed Oct 13, 2026
View reviewed changes

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5ebf7b8984

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread site/src/pages/AgentsPage/AgentSettingsSkillsPage.test.tsx Resolved

Uh oh!

There was an error while loading. Please reload this page.

@ibetitsmike
test(site/src/pages/AgentsPage): assert the member page's organizatio…
ac3e62c
…n switch through requests
@ibetitsmike

ibetitsmike commented Oct 13, 2026

Copy link
Copy Markdown
Collaborator Author

@codex review

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 13, 2026

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Breezy!

Reviewed commit: ac3e62c83b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@jaaydenh

jaaydenh commented Oct 13, 2026

Copy link
Copy Markdown
Contributor
Screenshot 2026-10-13 at 19 57 31

on the skills page, since it seems like the skills here are not intended to be editing on this page by any type of user, it could be a bit confusing to include an always disabled switch component. Instead this could be a checkmark for enabled and a X for disabled or something similar.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ibetitsmike
fix(site/src/pages/AgentsPage): show read-only skill status instead o…
63bb427
…f a disabled switch
@ibetitsmike

ibetitsmike commented Oct 13, 2026

Copy link
Copy Markdown
Collaborator Author

@jaaydenh good call, changed in 63bb427. When the viewer can't edit a skill, the Enabled column now shows a green check for enabled and a gray X for disabled, with "Enabled" and "Disabled" as the accessible names. Tables you can edit keep the switch.

This covers the "From your organizations" tables on this page and the admin Skills page for auditors, who can read but not edit. This page only lists enabled skills, so it shows checks only. A new ReadOnly story in SkillsTableView.stories.tsx shows both icons.

Xum replied on behalf of @ibetitsmike.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ibetitsmike

ibetitsmike commented Oct 13, 2026

Copy link
Copy Markdown
Collaborator Author

@codex review

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

chatgpt-codex-connector[bot]
chatgpt-codex-connector Bot reviewed Oct 13, 2026
View reviewed changes

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 63bb42754e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread site/src/pages/AISettingsPage/SkillsPage/SkillsPage.test.tsx Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread site/src/pages/AgentsPage/components/SkillsTable.test.tsx Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread site/src/modules/management/AISettingsSidebar.test.tsx Resolved

Uh oh!

There was an error while loading. Please reload this page.

jakehwll
jakehwll approved these changes Oct 13, 2026
View reviewed changes
jaaydenh
jaaydenh approved these changes Oct 13, 2026
View reviewed changes
@ibetitsmike
test(site/src): address Codex review on skills tests
82b2487
@ibetitsmike

ibetitsmike commented Oct 13, 2026

Copy link
Copy Markdown
Collaborator Author

@codex review

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 13, 2026

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

Reviewed commit: 82b2487ad1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

ibetitsmike added 4 commits October 13, 2026 14:45
@ibetitsmike
Merge main into data-model
5248d56
@ibetitsmike
Merge the updated data-model layer into org-api
18373ff
@ibetitsmike
Merge the updated org-api layer into sharing
c4d22c4
@ibetitsmike
Merge the updated sharing layer into settings-ui
658be8b
@ibetitsmike

ibetitsmike commented Oct 13, 2026

Copy link
Copy Markdown
Collaborator Author

@codex review

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 13, 2026

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. What shall we delve into next?

Reviewed commit: 658be8b8df

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

ibetitsmike added a commit that referenced this pull request Oct 13, 2026
@ibetitsmike
feat: add the organization skills data model (#30609)
b67587c
## Stack

Part of
[CODAGT-1341](https://linear.app/codercom/issue/CODAGT-1341/support-organization-level-skills-in-coder-agents).
This stack adds organization skills to Coder Agents: admins publish a
skill once per organization, share it with groups or members, and chats
in that organization load it next to personal and workspace skills. It
replaces the 21-PR draft stack #30584 to #30604 with five PRs, bottom to
top:

1. **#30609** data model: one migration, queries, RBAC and dbauthz (this
PR)
2. #30610 organization skill API routes and the scope-neutral SDK
3. #30611 sharing ACL routes
4. #30612 settings UI: shared skills table, admin page, member section
5. #30613 chats: chatd loading, `/` menu, docs

## What changes

This PR adds the data model and authorization for organization skills.
Personal skills keep working unchanged: `git diff origin/main --
codersdk site` shows only generated RBAC and API key scope additions
(`apikey_scopes_gen.go`, `rbacresources_gen.go`,
`rbacresourcesGenerated.ts`, the RBAC and scope unions in
`typesGenerated.ts`) and `codersdk.ResourceTypeOrganizationSkill` with
its friendly string. No personal route, SDK type or site component
changes, and `coderd/userskills_test.go` changes only by mechanical
constant renames.

**One migration, `000621_skills`** (please review it closely):

- renames `user_skills` to `skills` with its constraints, index and
triggers, and recreates the cap function and
`delete_deleted_user_resources`, whose PL/pgSQL bodies name the table;
- adds `organization_id` and `project_id` (`ON DELETE CASCADE`),
`enabled` (default true), and `group_acl` / `user_acl` (`jsonb`, default
`{}`), with CHECKs for exactly one owner, ACLs that are JSON objects,
and ACLs that stay empty unless an organization owns the row, plus
partial unique name indexes per owner kind;
- replaces the cap trigger with `enforce_skills_per_owner_limit()`: 100
rows per owner, disabled rows included, locking the owner row `FOR NO
KEY UPDATE` so unrelated foreign key checks are not blocked;
- adds a `BEFORE DELETE` trigger on `organization_members` that removes
a departing member from `user_acl` on that organization's skills, so
rejoining doesn't restore a direct grant;
- adds the `organization_skill` `resource_type` and `api_key_scope` enum
values last; nothing in the migration uses them.

The down migration undoes the three old migrations in reverse order: it
drops organization and project rows and restores `user_skills`, its
names, the cap function and `user_id NOT NULL`.

Authorization: a new RBAC resource `organization_skill` (create, read,
update, delete, share). Owner and org admin get it; site and org
auditors get read; members read only through the skill's ACL, which
applies only to members of its organization. `Skill.RBACObject()`
returns the organization object with both ACLs; project rows stay denied
to everyone. New sqlc queries cover organization insert, get, list
(SQL-filtered through `GetAuthorizedOrganizationSkillMetadata` and a
`regosql` converter), update and delete, with dbauthz wrappers and the
audit table entries. No routes yet.

## Commits

The first commit reproduces the reviewed code from the old stack; each
later commit is a labeled trim or fix.

- `baa3150e3b7` feat: add the organization skills data model.
Reproduction: every non-site file this commit changes equals the
reviewed old `authz` head `1e16b3004c4`, except that the old stack's
migrations 000615, 000616 and 000617 are merged into one migration (then
`000615_skills`, now `000621_skills`) with one fixture
(`testdata/fixtures/000621_skills.up.sql`) and one migration test (now
`testMigration000621Skills`). At that commit, `dump.sql` was
byte-identical to the old head's.
- `1b84e83463a` test(coderd/database): keep only the SQL paths of the
org skill matrix. `TestOrganizationSkillAuthorization` becomes
`TestOrganizationSkillQueries` instead of being deleted, because
coverage showed it is this PR's only run of the
`GetAuthorizedOrganizationSkillMetadata` row scan (80% to 65% without
it) and of the organization update and delete queries (100% to 0%).
Swapping `group_acl` and `user_acl` in the converter makes
`GrantedMember` fail. The removed cases are decided by
`TestRolePermissions`, `TestSkillRBACObjectOrganizationACL` and the
dbauthz method suite.
- `e2931b412e9` test(coderd/database): fold the skill cap cases into
existing coverage. The user case is covered by `TestUserSkillLimit` and
`TestUserSkillLimitConcurrentCreates`; the organization case folds into
`ConcurrentOrganizationInsertsHonorCap`, which now also checks that
disabled rows count and another organization is unaffected (mutation
checked); the project case stays.
- `be62aea9021` test(coderd/rbac): drop
`TestOrganizationSkillReadScope`, covered by `TestExternalScopeNames`
and the generated scope file.
- `0c275ba37de` merges main at `454a2fcc697`, which took 000615 to
000618: it renumbers the migration to 000619 and resolves `dump.sql`,
`check_constraint.go` and the generated API docs. `8f2b4b87ee2` merges
main at `ad85646164e`, which took 000619: it renumbers the migration to
000620.
- `5248d56b64f` merges main at `e7b76872098`, which took 000620
(`000620_audit_chat_project_instructions_resource_type`): it renumbers
the migration, fixture and migration test to `000621_skills` (step
`Migration000621Skills`, version 621), and resolves
`enterprise/audit/table.go` (keeping main's
`AuditableChatProjectInstructions` entries and the `Skill` entry),
`dump.sql` and `models.go` (the `resource_type` enum gets
`chat_project_instructions`, then `organization_skill`) and the
regenerated `schemas.md`. The up and down SQL are unchanged by every
renumbering.

## Size

Production +549/-67, tests +728/-33, generated +881/-314; total
+2158/-414. This is above the 500-line reviewer-friendly limit on
purpose: Mike asked for 4 to 5 PRs instead of the 21 small ones this
stack replaces.

## Replaces

#30584 (rename `user_skills` to `skills`), #30585 (skill owners), #30586
(organization skill authorization).

## Validation

- Migration test: up keeps the existing personal row and its ID; down
restores the `user_skills` names, cap function and `NOT NULL`, and drops
organization rows; soft-deleting a user removes their skills after up,
after down, and after re-up.
- `go test` passed on `be62aea9021`, before the main merges, for
`coderd` (skill tests), `coderd/database`, `dbauthz`, `migrations`,
`gentest`, `coderd/rbac/...`, `coderd/x/chatd`, `coderd/x/skills`,
`enterprise/audit` and `enterprise/coderd`; `make lint/check-scopes`
passed; the four personal skills Vitest files pass unchanged.
- On `5248d56b64f`: build, vet, `TestMigrate`, `TestMigrationChain`, the
`migrations`, `database`, `dbauthz`, `gentest`, `rbac` and
`enterprise/audit` packages pass; `make gen` run twice is clean, and
`make pre-commit` passes.
- Remote UAT round 7 through Coder Agents passed on the whole stack; see
#30613's Validation for scope and findings.

> Xum opened this PR on behalf of @ibetitsmike.
ibetitsmike added a commit that referenced this pull request Oct 13, 2026
@ibetitsmike
feat: add organization skill API routes (#30610)
db7f5a7
## Stack

Part of
[CODAGT-1341](https://linear.app/codercom/issue/CODAGT-1341/support-organization-level-skills-in-coder-agents).
This stack adds organization skills to Coder Agents: admins publish a
skill once per organization, share it with groups or members, and chats
in that organization load it next to personal and workspace skills. It
replaces the 21-PR draft stack #30584 to #30604 with five PRs, bottom to
top:

1. #30609 data model: one migration, queries, RBAC and dbauthz
2. **#30610** organization skill API routes and the scope-neutral SDK
(this PR)
3. #30611 sharing ACL routes
4. #30612 settings UI: shared skills table, admin page, member section
5. #30613 chats: chatd loading, `/` menu, docs

## What changes

This PR adds the organization skill CRUD routes and makes the skill SDK
types owner-neutral so personal and organization skills share them.

**API contract change (experimental API, personal and organization
skills):** skill list and get responses gain `enabled`, and `PATCH
.../skills/{skillName}` now takes `{content?, enabled?}`, so `content`
is optional and a toggle doesn't resend it. A PATCH with neither field
returns 400; `content`, when present, is validated as before. In the
SDK, `UserSkill`, `UserSkillMetadata`, `CreateUserSkillRequest` and
`UpdateUserSkillRequest` become `Skill`, `SkillMetadata`,
`CreateSkillRequest` and `UpdateSkillRequest` (`codersdk/userskills.go`
moves to `codersdk/skills.go`), and `UpdateSkillRequest.Content` is now
`*string`. The personal client method names are unchanged. The site
changes are the handwritten edits that rename forces (`api.ts`,
`queries/userSkills.ts`, `testHelpers/skills.ts` and three call sites),
with no UI change.

Organization routes under
`/api/experimental/organizations/{organization}/skills`, not gated by an
experiment or license, like the personal ones:

- `GET` lists with the caller's own permissions, so admins, the site
owner and org auditors see every skill and members see only skills
shared with them. `GET /{skillName}` goes through the new
`httpmw.ExtractOrganizationSkillParam` and admits only read, so a
missing skill and a denied one both return 404.
- `POST` checks `create` on the organization before reading the body,
then seeds `group_acl` with the Everyone group (whose ID is the
organization ID) so a new skill reaches every member until an admin
narrows it. The 100-skill cap and a duplicate name return 409.
- `PATCH` admits only callers who can read the skill, because its
response includes the content; `DELETE` admits callers who can read or
delete it. A reader who can't change the skill gets a write-specific 403
from the database wrapper, and everyone else gets 404. PATCH locks the
row as system, updates as the caller in the same transaction, and audits
the locked row only after the transaction commits.
- Audit: `database.AuditableOrganizationSkill` records resource type
`organization_skill` with the organization ID; personal skills keep
`user_skill`.

Personal and organization handlers share one create and update path in
`coderd/userskills.go` (`createSkill`, `updateSkill`, and a
`skillWriteErrors` table per owner and action).

## Commits

The first commit reproduces the reviewed code from the old stack; each
later commit is a labeled trim or fix.

- `49cb2c84276` feat: add organization skill API routes. Reproduction:
every file this commit changes, including the SDK layer's site edits,
equals the reviewed old `write-routes` head `aa597100f28`; the rest of
the tree differs only by #30609's migration merge and main.
- `dc893bc60d6` refactor(coderd): share the skill create and update path
across owners (production +164/-188). It keeps the organization create
check before the body read, the lock as system then update as caller
order, and audit assignment after the transaction. No swagger,
`codersdk` or `typesGenerated.ts` change; `make gen` is clean.
- `f94925425ef` test(coderd): merge duplicate personal and organization
skill tests. `TestSkillsCRUD`, `TestSkillValidationAndConflicts` and
`TestSkillAudit` are table-driven over Personal, OrgAdmin and SiteOwner,
alongside `TestOrganizationSkillAuditsDeniedWrites` and one
`ScopedAPIKeys` subtest; `TestPatchUserSkill` is deleted because none of
its blocks were unique. Coverage of `userskills.go`,
`organizationskills.go` and `httpmw/organizationskillparam.go` is 101 of
117 blocks before and after, the same block set.
- `ad0a7a37504` fix(coderd): require read access to patch an
organization skill. The organization PATCH route now admits only `read`,
because its response carries the skill's content: a key scoped to
`organization_skill:update` without read gets 404, like GET, instead of
200 with the content. Readers without update still get 403, and DELETE
is unchanged. `TestOrganizationSkillAccess/ScopedAPIKeys` asserts the
404, that the response has no content, and that the skill is unchanged;
against the old route it fails with 200.
- `69d00ded0b6` and `f67b79343ec` merge the updated #30609 layer,
including main; `69d00ded0b6` resolves a conflict in the personal skills
page with main. No other changes of their own.
- `18373ffd59e` merges the updated #30609 layer (main at `e7b76872098`)
and reapplies the `AuditableOrganizationSkill` entry in
`enterprise/audit/table.go` alongside main's new
`AuditableChatProjectInstructions` entries.

## Size

Production +838/-308, tests +733/-322, generated +801/-274; total
+2372/-904. This is above the 500-line reviewer-friendly limit on
purpose: Mike asked for 4 to 5 PRs instead of the 21 small ones this
stack replaces.

## Replaces

#30587 (scope-neutral SDK and personal enabled state), #30588 (read
routes), #30589 (write routes and audit).

## Validation

- The coverage comparison above, before and after the test merge.
- `make gen` leaves no diff after the shared create and update refactor.
- On `18373ffd59e`: `make gen` is clean; build, vet, the `coderd` and
`enterprise/coderd` skill tests, `rbac`, `httpmw`, `dbauthz` and
`enterprise/audit` pass; `pnpm check`, `pnpm lint` and `make pre-commit`
pass.
- Remote UAT round 7 through Coder Agents passed on the whole stack; see
#30613's Validation for scope and findings.

> Xum opened this PR on behalf of @ibetitsmike.
@ibetitsmike
ibetitsmike requested a review from nickvigilante as a code owner October 13, 2026 16:24
Base automatically changed from mike/skills/sharing to main October 13, 2026 16:43
ibetitsmike added a commit that referenced this pull request Oct 13, 2026
@ibetitsmike
feat: add organization skill sharing ACL routes (#30611)
2c432a1
## Stack

Part of
[CODAGT-1341](https://linear.app/codercom/issue/CODAGT-1341/support-organization-level-skills-in-coder-agents).
This stack adds organization skills to Coder Agents: admins publish a
skill once per organization, share it with groups or members, and chats
in that organization load it next to personal and workspace skills. It
replaces the 21-PR draft stack #30584 to #30604 with five PRs, bottom to
top:

1. #30609 data model: one migration, queries, RBAC and dbauthz
2. #30610 organization skill API routes and the scope-neutral SDK
3. **#30611** sharing ACL routes (this PR)
4. #30612 settings UI: shared skills table, admin page, member section
5. #30613 chats: chatd loading, `/` menu, docs

## What changes

This PR adds the routes that let admins choose who can read an
organization skill. It reuses the MCP server ACL machinery rather than
adding a second implementation.

Routes under
`/api/experimental/organizations/{organization}/skills/{skillName}`, all
behind `httpmw.ExtractOrganizationSkillParam` with `share`, so a caller
without share gets 404:

- `GET /acl` returns the resolved user and group grants.
- `GET /acl/available` returns the organization's users and groups that
can be granted, with the same `q`, `after_id`, `limit` and `offset`
paging as the MCP endpoint.
- `PATCH /acl` takes a sparse `UpdateOrganizationSkillACLRequest`: only
the listed principals change, `read` grants and `""` removes. It returns
204 and writes a `write` audit entry with the old and new ACL.

**Concurrency (please review closely):** the PATCH transaction first
locks the granted users' `organization_members` rows `FOR KEY SHARE`
(new query `LockOrganizationMembersByUserIDsForShare`, run as system),
then locks the skill row `FOR UPDATE`, then validates the update on the
transaction handle. Member removal takes the same locks in the same
order (its membership row, then the skill rows through the #30609
trigger), so the two can't deadlock, and a removal can't miss a grant
written by a concurrent PATCH. A skill deleted between the middleware
read and the row lock stays a 404.

Grants are users and groups, the same as MCP server configs (Mike's
decision, for parity). Only the `read` role exists; any other role is a
validation error, as are users or groups outside the organization.

Supporting changes:

- `coderd/mcp_acl.go`: the MCP ACL handlers' resolution, candidate
listing and validation move into generic helpers
(`writeOrganizationACLAvailable`, `validateOrganizationACLUpdate`,
`resolveACLUsers`, `resolveACLGroups`) shared by both resources;
`acl.Validate` accepts a named `acl.Role` constraint that now includes
`codersdk.OrganizationSkillRole`.
- `codersdk/skills.go`: `OrganizationSkillRole`, `OrganizationSkillACL`
with its user and group entries, `UpdateOrganizationSkillACLRequest`,
and client methods.
- New sqlc query `UpdateOrganizationSkillACLByID` with its dbauthz
wrapper (requires `share`).

## Commits

The first commit reproduces the reviewed code from the old stack; each
later commit is a labeled trim or fix.

- `b1c85560b69` feat: add organization skill sharing ACL routes.
Reproduction: every file this commit changes equals the reviewed old
`acl-routes` head `80c1c3594e6`; the rest of the tree differs only by
#30609's migration merge and main.
- `b5d2ee265c8` test(coderd): merge duplicate organization skill ACL
route tests (+49/-111). The removed cases repeated
`TestMCPServerConfigACL`, `TestMCPServerConfigACLAvailable` or
`TestRolePermissions`; with the MCP tests included, the covered block
set of `organizationskills_acl.go`, `mcp_acl.go` and
`rbac/acl/updatevalidator.go` is identical before and after. Kept:
`TestOrganizationSkillACL` (`OrgAdminManagesACL`, `ReadersGetNotFound`,
`SparseUpdateChangesReaders` with the audit diff,
`RejectsUnsupportedRole`, `ScopedAPIKeys`),
`TestOrganizationSkillACLConcurrentDelete`, and the lock order tests
`TestOrganizationSkillACLMemberRemoval` (`RemovalBeforeGrant`,
`RemovalAfterGrant`). `OrgAdminManagesACL` now also checks that users
from another organization are not candidates (mutation checked). Sharing
the param extractor with MCP was skipped: it would save about 10 lines
of security-sensitive code.
- `e09c4dba66b` Merge the updated org-api layer into sharing. Brings in
#30610's `ad0a7a37504`; the merge has no changes of its own.
- `1d3817dc639` and `c8c88f84d18` merge the updated #30610 layer,
including main; no changes of their own.
- `c4d22c47990` merges the updated #30610 layer (main at `e7b76872098`);
no changes of its own.

## Size

Production +431/-102, tests +377/-0, generated +918/-0; total
+1726/-102. This is above the 500-line reviewer-friendly limit on
purpose: Mike asked for 4 to 5 PRs instead of the 21 small ones this
stack replaces.

## Replaces

#30591 (ACL queries), #30592 (ACL routes).

## Validation

- `go build` and `go vet` passed; `make gen` exited 0 with no diff.
- `go test` passed for `coderd` (skill, MCP and ACL tests),
`coderd/database`, `dbauthz`, `migrations`, `gentest`,
`coderd/rbac/...`, `coderd/httpmw`, `coderd/x/skills/...`,
`coderd/x/chatd/...`, and the audit and skill tests in
`enterprise/audit` and `enterprise/coderd`.
- The covered block comparison above, before and after the test merge.
- On `c4d22c47990`: the same checks as #30610's head, plus `go test
./coderd/ -run 'Skill|MCP|ACL'`, pass.
- Remote UAT round 7 through Coder Agents passed on the whole stack; see
#30613's Validation for scope and findings.

> Xum opened this PR on behalf of @ibetitsmike.
@ibetitsmike
Merge main into settings-ui
8622058
@ibetitsmike
ibetitsmike merged commit 6498c57 into main Oct 13, 2026
27 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@ibetitsmike
ibetitsmike deleted the mike/skills/settings-ui branch October 13, 2026 16:57
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 13, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Reviewers

@chatgpt-codex-connector chatgpt-codex-connector[bot] chatgpt-codex-connector[bot] left review comments
@jaaydenh jaaydenh jaaydenh approved these changes
@jakehwll jakehwll jakehwll approved these changes
@nickvigilante nickvigilante Awaiting requested review from nickvigilante

Uh oh!

There was an error while loading. Please reload this page.

Assignees

@ibetitsmike ibetitsmike

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

3 participants

@ibetitsmike @jaaydenh @jakehwll
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.