Add a new file type to the matrx-admin file system, or enhance any of the ~55 capability slots on an existing one (preview, edit, thumbnail, grid card, info, analysis, share, versions, control rail, action bar, conversion, diff, etc.). Use when adding support for a file extension, building a new previewer, expanding the `PreviewKind` union, modifying `FILE_TYPES`, touching `FilePreview.tsx` / `FileTabsBody.tsx` / `CloudFileInlineEditor.tsx` / `preview-actions.ts` / `EDITABLE_KINDS` / `LANGUAGE_BY_EXT`, building or editing a rail panel under `features/files/components/surfaces/single-file/`, wiring `FileViewerControlsContext`, or working an item off the wishlist in `/Users/armanisadeghi/code/common-docs/systems/media/file-service/FILE_SURFACES.md`.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
Add a new file type to the matrx-admin file system, or enhance any of the ~55 capability slots on an existing one (preview, edit, thumbnail, grid card, info, analysis, share, versions, control rail, action bar, conversion, diff, etc.). Use when adding support for a file extension, building a new previewer, expanding the `PreviewKind` union, modifying `FILE_TYPES`, touching `FilePreview.tsx` / `FileTabsBody.tsx` / `CloudFileInlineEditor.tsx` / `preview-actions.ts` / `EDITABLE_KINDS` / `LANGUAGE_BY_EXT`, building or editing a rail panel under `features/files/components/surfaces/single-file/`, wiring `FileViewerControlsContext`, or working an item off the wishlist in `/Users/armanisadeghi/code/common-docs/systems/media/file-service/FILE_SURFACES.md`.
Enhance a file type
The matrx-admin file system has one registry (FILE_TYPES), one preview dispatcher (FilePreview.tsx), one edit dispatcher (FileTabsBody.tsx → EditTabContent), and two viewer shells (PreviewPane side panel + SingleFileShell full page). A "complete" file type touches ~55 capability slots organized into 9 groups (Identity, List/Grid, Preview, Edit, Companion tabs, Actions, Cross-feature, Creation, Bundle). Every kind lives somewhere on a T0 → T1 → T2 curve and the inventory tracks both current state and per-type wishlists.
Use this skill when
Adding a new file extension or MIME type to the registry
Building a new <Kind>Preview previewer or upgrading an existing one
Adding a previewKind to the PreviewKind union
Wiring the Edit tab for a new kind (extending EDITABLE_KINDS and Monaco's LANGUAGE_BY_EXT)
Building a rail panel in surfaces/single-file/ for a new editing/preview mode
Adding a new control to FileViewerControlsContext
Working any item off FILE_SURFACES.md (common-docs)'s per-type wishlist
Upgrading a thumbnail strategy, Info-tab field, Analysis detector, or action-bar button for a specific kind
Full slot list (numbered 1–55) lives in /Users/armanisadeghi/code/common-docs/systems/media/file-service/FILE_SURFACES.md → Part 1 — Capability framework. Read that section before scoping any non-trivial change.
Workflow
Copy this checklist and tick items as you go:
- [ ] Step 1 — Scope: identify file type + capability slot
- [ ] Step 2 — Read the inventory entry for that type
- [ ] Step 3 — Map the slot to code surfaces (use the table below)
- [ ] Step 4 — Implement (≤4 files for most changes)
- [ ] Step 5 — Verify in both PreviewPane and SingleFileShell
- [ ] Step 6 — Run lints + tsc
- [ ] Step 7 — Update FILE_SURFACES.md (common-docs) (matrix + wishlist + priorities)
- [ ] Step 8 — Update features/files/FEATURE.md change log
Step 1 — Scope
Decide one of:
A. New file extension to an existing previewKind — e.g. add .heif to image. Single registry change.
B. New previewKind — e.g. add Jupyter notebook renderer. Touches the PreviewKind union, the registry, the preview dispatcher, and a new previewer file.
C. Capability upgrade on an existing kind — e.g. add click-and-drag pan to Image, or wire the PDF Extractor into the PDF Edit tab. Touches the previewer/rail/context.
D. Cross-cutting capability — e.g. add format-on-save (slot #28), or add convertTo to the action bar (slot #42). Touches the platform, then per-kind opt-in.
If unsure which slot a request maps to, scan Part 1 of the inventory.
Step 2 — Read the inventory entry
Open /Users/armanisadeghi/code/common-docs/systems/media/file-service/FILE_SURFACES.md and read:
Part 2's wishlist for the type you're touching (Image / PDF / HTML / Markdown / Video / Code — these have full per-type wishlists today). If your type doesn't have a Part 2 entry yet, find it in Part 3's matrix.
Part 1 to confirm which slot # you're filling.
If your work fulfills a wishlist item, you'll be checking it off in Step 7.
Step 3 — Map the slot to code
Use this table. Match the slot number to the file(s) you'll touch:
Slots
Files to touch
1–9 (Identity)
features/files/utils/file-types.ts → FILE_TYPES[]
10–12 (Icon / thumb strategy)
file-types.ts + FileIcon; for real thumbs: useFileAsset variants
13–14 (Grid card / quick-look)
Grid card components in features/files/components/... (search for FileGridCard)
15 (Kind-filter chip)
Kind filter chip data
17–23 (Preview tab)
core/FilePreview/FilePreview.tsx (dispatcher), previewers/<Kind>Preview.tsx, optional surfaces/single-file/<Mode>Controls.tsx for the rail, surfaces/FileViewerControlsContext.tsx if you need new shared state
If editable: add "<kind>" to EDITABLE_KINDS + ensure EditTabContent routes it
If it has interactive controls in SingleFileShell: add a <Mode>Controls.tsx panel + register it in FileViewerControlRail, and add any shared state to FileViewerControlsContext
Pattern C — Upgrade an existing previewer
Make the change in previewers/<Kind>Preview.tsx
If it introduces new rail state: extend FileViewerControlsContext (typed props + setters)
Add/extend the matching <Mode>Controls.tsx panel
Verify the previewer still works without context (passive mode in PreviewPane)
Step 5 — Verify in both surfaces
This is the #1 thing agents get wrong. Previewers run in two surfaces:
PreviewPane — side panel from the files browser. The FileViewerControlsContext is NOT mounted here. Previewers must work in passive mode with no rail.
SingleFileShell — dedicated /files/f/{id} route. The rail is mounted, context is populated, controls drive the previewer.
Test paths:
https://www.aimatrx.com/files → click a file row → verify side-panel preview works
https://www.aimatrx.com/files/f/{id} → verify full-page preview + rail controls work
Previewers should useFileViewerControls()-style read context but never require context. Always have a sensible default.
Open /Users/armanisadeghi/code/common-docs/systems/media/file-service/FILE_SURFACES.md and update:
Part 3 (matrix) — change the ✅/🟡/🔴/🐛 marker in the relevant row + update the Notes column
Part 2 (wishlist) — if you completed a wishlist item, either strike it through (~~item~~ ✅ **Shipped.** …) or remove it. Add any newly-discovered follow-up items.
Priority recommendations (end of doc) — if your work knocked out a numbered item, mark it shipped the same way HTML and Image were.
If you added a new previewKind or graduated a kind to T1/T2, add a new Part 2 entry following the template (Has / Wishlist / Code touchpoints).
Step 8 — Update the feature doc
Append a one-line entry to features/files/FEATURE.md's Change Log with the date and a summary. If your change touches an invariant (e.g. "previewers must work without rail context"), update that section too.
Common pitfalls
Forgetting EDITABLE_KINDS. Adding Monaco support without adding the kind to EDITABLE_KINDS means the Edit button stays hidden.
Forgetting Monaco's LANGUAGE_BY_EXT. Adding a previewKind: "code" extension without a LANGUAGE_BY_EXT entry opens it as plaintext in Monaco — no syntax highlighting in Edit.
Tightly coupling a previewer to the rail context. Previewers run in PreviewPane (no rail) AND SingleFileShell (with rail). Read useFileViewerControls() with a default fallback, never require it.
Size-cap mismatch. Streaming previewers (image, video, audio, pdf, html) should override previewSizeCapOverride via getFilePreviewProfile — they don't blob-fetch the whole file. Non-streaming previewers respect the default cap.
Sandbox policy on HTML-like content. The HTML iframe sandbox is allow-scripts allow-popups allow-forms and does not include allow-same-origin. Anything that needs cookies/localStorage cannot run there — and shouldn't.
Skipping the Part 2 update. The wishlist is the operating doc. If you ship a wishlist item without checking it off, the next agent will think the work is still open.
Adding a new top-level .md for the new feature. Don't. One doc per concern — extend FILE_SURFACES.md (common-docs) and the file's FEATURE.md.
Decision matrix — which surface holds the control?
When a previewer needs an interactive control (zoom, viewport, line-wrap, …):
Where the control belongs
When
Inline in the previewer's own header
The control is fundamental to viewing (e.g. Rendered/Source toggle for HTML). Must work in PreviewPane.
In a single-file/<Mode>Controls.tsx rail panel
The control is power-user / space-intensive (zoom slider, viewport picker, font size, minimap toggle). Only mounted in SingleFileShell.
Both
Provide a minimal version inline and a richer version on the rail. The inline version reads FileViewerControlsContext if mounted, else its own local state.
Default: rich controls on the rail, with a sensible default applied when the previewer renders without context.
Bundle budget
Previewers are dynamically imported (next/dynamic). Heavy deps (PDF.js, SheetJS, Three.js when added) must stay dynamic — never import them at the top of FilePreview.tsx or any of its eagerly-loaded ancestors. Annotate bundle weight in FilePreview.tsx if it's non-trivial.
Pre-PR checklist
Registry entry has all 9 Group-1 fields populated (or N/A justified)
Previewer renders in PreviewPane (no rail) without errors
Previewer renders in SingleFileShell (with rail) with controls wired
If editable: EDITABLE_KINDS and LANGUAGE_BY_EXT both updated
Lints pass, tsc --noEmit passes
FILE_SURFACES.md (common-docs) Part 3 markers updated for affected rows
FILE_SURFACES.md (common-docs) Part 2 wishlist entries struck through / amended
FILE_SURFACES.md (common-docs) Priority recommendations updated if a numbered item shipped