extending-the-admin-console
Skill728 starsChanged 8 days agoMITView on GitHub
Add or change what staff see and do in PostHog Admin, the staff console at /admin/console/. Use when adding a panel to a team page, a staff action (an operation), or a cross-team report (a tool) in a `console.py`, when moving a button, view or page out of Django admin into the console, or when asked to "add an admin action", "add a staff tool", "show X to support in admin", or to touch `posthog/admin/console/` or `posthog/templates/admin_console/`. Covers choosing panel vs tool vs Django admin, the data-only contract, copy, danger operations, replacing the old Django admin entry point, and the checks before calling it done.
In this repository125 other files it gives its agents.
- AGENTS.mdAGENTS.md
- common/AGENTS.mdAGENTS.md
- hog/AGENTS.mdAGENTS.md
- proto/AGENTS.mdAGENTS.md
- rust/AGENTS.mdAGENTS.md
- .cursor/rules/django-python.mdcCursor rule
- .cursor/rules/react-typescript.mdcCursor rule
- .cursor/rules/rust.mdcCursor rule
- adding-activity-loggingSkill
- adding-api-scopesSkill
- adding-inbound-webhooksSkill
- adding-inbox-sourcesSkill
- adding-ingestion-warningsSkill
- adding-mcp-store-serversSkill
- adding-personhog-rpcSkill
- adding-product-alertingSkill
- adding-project-secret-api-key-authSkill
- adding-today-highlightsSkill
- adopting-generated-api-typesSkill
- analyzing-experiment-precompute-canarySkill
- analyzing-experiment-query-performanceSkill
- analyzing-insights-across-teamsSkill
- announcing-behavior-changesSkill
- auditing-llm-gateway-paritySkill
- auditing-warehouse-source-coverageSkill
- authenticating-to-clickhouseSkill
- authoring-ci-workflowsSkill
- building-product-empty-statesSkill
- building-the-toolbarSkill
- clickhouse-migrationsSkill
- debugging-ci-failuresSkill
- debugging-local-replaySkill
- debugging-local-task-agent-runsSkill
- debugging-mcp-analyticsSkill
- debugging-signals-pipelineSkill
- debugging-table-access-deniedSkill
- depot-ciSkill
- depot-container-buildsSkill
- depot-github-runnersSkill
- developing-subscriptionsSkill
- django-migrationsSkill
- django-startup-timeSkill
- documenting-warehouse-sourcesSkill
- editing-agents-mdSkill
- establishing-code-ownershipSkill
- extending-hobby-smoke-testsSkill
- extending-personhog-test-harnessSkill
- finding-llm-gateway-migration-candidatesSkill
- fixing-flaky-testsSkill
- formatting-slack-messagesSkill
- gating-production-deploysSkill
- gating-sensitive-actionsSkill
- generating-clickhouse-query-performance-reportsSkill
- hogliSkill
- implementing-mcp-toolsSkill
- implementing-mcp-ui-appsSkill
- implementing-warehouse-sourcesSkill
- improving-drf-endpointsSkill
- improving-mcp-toolsSkill
- ingestion-pipeline-doctor-nodejsSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
6 rules. About 0 are common, 2 are distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 10
Read posthog/admin/console/AGENTS.md first.
- Distinctive: line 25
Do not repeat facts another panel shows (team ID, organization, API token are in Overview).
- Very specific: line 33
Use the words staff see in the app, not field names.
- Very specific: line 52
When a whole page moves, keep its old URL name and route it to MovedToConsole.page_redirect, which tells staff the page moved.
- Very specific: line 58
Run pnpm --filter=@posthog/frontend build:admin-console when you add an owner crest.
- Distinctive: line 60
Put a screenshot of the panel in the PR description.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Extending the admin console
PostHog Admin is a shared surface. Every team adds to it, and staff use it under pressure, often while a customer waits.
Consistency is the feature: a panel that looks and reads like every other panel is one staff can use without thinking.
Read posthog/admin/console/AGENTS.md first. It holds the invariants and the add-a-panel and add-a-tool recipes. This skill holds the judgment around them.
1. Decide where it goes
- Plain create, read, update or delete on one model stays in Django admin. The console is not a second CRUD layer.
- Facts and actions about one team or one organization go in a panel on that record's page. One panel per product concern, owned by the team that owns the data.
- A report across many teams, or an action that is not about one record (a backfill, a re-save across teams) is a tool. An action on one team from a tool row links to that team's page instead of becoming a tool operation.
- A staff page your product already has in the app (a DRF staff endpoint and scene) is legacy. Do not extend it and do not bridge to it. Ask the user whether to move it into the console as its own change.
- Anything else (a new record type such as a user or project page, a new block kind, a new tool group, a template change) is a shell change. Stop and ask the user: those need a review by the console owners (team-devex), not a product team alone.
2. Write the panel or tool as data
- Return
Fact,Operationand tool blocks only. The contract rejects markup, unknown blocks and bad keys at import or render time, so fix the contribution, not the check. - Keep the logic out of
console.py. Facts and handlers call your product's facade or a service function, even when the product is not isolated yet.console.pyis an adapter, like a view: no ORM queries, no.delay()calls, no cache clients. A small dataclass the facade returns goes where products/architecture.md puts facade contracts. - Show at most
MAX_FACTS_PER_PANELfacts. Pick the ones that answer the questions staff ask in a ticket. History and long lists belong in a tool. - Do not repeat facts another panel shows (team ID, organization, API token are in Overview).
3. Copy
Invoke /writing-user-facing-copy. In the console that means:
- Sentence case for titles, labels and buttons. Keep proper nouns and acronyms as they are (API, AI, ClickHouse).
- An operation label starts with a verb and names the effect: "Suspend email sending", not "Email" or "Submit".
- Use the words staff see in the app, not field names. "Revoked" beats
llm_gateway_revoked_at. - An
Operation.descriptionsays what happens to the customer, for example "The team gets an email".
4. Classify every operation
- Read only needs no operation at all. Make it a fact.
- Internal and reversible (rebuild, clear or purge a cache that refills itself) is a plain operation.
- Gives the customer something back (enable access, clear a revoke, re-enable sending, add credit) is a plain operation. Give it a form only when it needs input, as Add credit does for the amount and the reason.
- Takes something away from the customer, or cannot be undone (suspend, revoke, replace a token) sets
danger=True, takes a form with areasonfield, and setsundo_hintto how staff undo it, or that they cannot. The console writes the reason to the audit log and shows the undo hint on the confirm page. - Only the owning team's staff may run it (approve a deletion, send usage reports): set
gate=Gate.owner(), and setstaff_groupon the panel or tool'sOwnerto that team's Django group. UseGate.group(name)only when the operation belongs to another team's group. - A handler that moves money or sends messages builds its idempotency key from the
form_noncethe console posts, so a double submit runs once. - Offer an operation only in the state where it makes sense. The console runs only operations the panel offers right now.
- A form that edits current state sets
form_initialfrom the record, so an unchanged submit changes nothing. - To report a failure, a handler adds an error message and returns a 4xx or 5xx response. For an operation with a form, the console then shows the form again with what staff typed.
5. Move a Django admin action without losing anyone
- Point the operation at the old view with
AdminViewBridge(Model, SomeAdmin.view_method)while the logic still lives in theModelAdmin. - Replace the old button in Django admin with
MovedToConsole.action("<record>", obj, "<panel-key>", "<what moved>"), so staff who look in the usual place find the new one. - When a whole page moves, keep its old URL name and route it to
MovedToConsole.page_redirect, which tells staff the page moved. - Every old URL keeps working, query parameters included. Support staff keep bookmarks to old admin pages and actions. When you delete a record action's view, add its old path to the
MOVED_*_ACTIONSmap of its record type inposthog/admin/console/urls.py, so it redirects to the console form or panel.
6. Before you call it done
- Extend
posthog/admin/test_admin_console.py: add the panel title to the record page test, and a parameterized case for each new operation's success and refusal. Do not add a new test file. - Run
pnpm --filter=@posthog/frontend build:admin-consolewhen you add an owner crest. Commit the output. - Open the record page (
/admin/console/teams/<id>/or/admin/console/organizations/<uuid>/) on the local stack (log in astest@posthog.com) and look at the page at a narrow and a wide window. A panel that reads wrong in the browser is not done, whatever the tests say. - Put a screenshot of the panel in the PR description.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

