AGENTS.md Swift Frontend

palmier-pro — AGENTS.md

macOS video editor built for AI

AGENTS.md · 129 lines
# PalmierPro

AI-native macOS video editor. Swift 6.2, SwiftUI + AppKit, AVFoundation. macOS 26 only, arm64 only. Non-sandboxed Developer ID app.

## Build

```bash
swift build
swift run
swift test
```

Use `swift build --traits BundledSpeech` for changes that touch MLX, speech analysis, transcription, or bundled speech resources.

## Engineering approach

- Understand the owning feature and existing abstractions before editing. Trace the complete call path, including UI, Agent tools, undo, persistence, and background work.
- For nontrivial changes, identify the source of truth, state owner, isolation domain, invariants, failure behavior, cancellation behavior, and file placement before writing code.
- Design the architecture before adding implementation details. Prefer a small coherent change over patches spread across unrelated layers.
- Keep one authoritative owner for mutable state. Derived state must be computed or maintained by a cache with an explicit invalidation contract.
- Reuse existing domain operations. Do not create a second implementation because the caller is a preview, SwiftUI view, AppKit controller, Agent tool, or test.
- Preview, validation, execution, persistence, and undo must share the same eligibility rules, calculations, clamping, timing, placement, and mutation helpers.
- Place code with the feature that owns it. Use `Utilities` only for infrastructure used by multiple independent features.
- Split extensions by coherent capability, not arbitrary file length. File and type names must make ownership clear.
- SwiftUI views render state and forward user intent. Keep domain mutations, filesystem work, media processing, and orchestration out of view bodies.
- Follow the Swift API Design Guidelines. Optimize names for clarity at the call site and use established filmmaking and Apple-platform terminology.

## Code style

- Keep comments minimal. Write one only when the why, invariant, safety constraint, or framework workaround is non-obvious.
- Comments are one short line maximum. Do not narrate code, restate names, describe the current patch, leave removal breadcrumbs, add commented-out code, or write paragraph docstrings for internal APIs.
- Prefer precise names, small types, and extracted operations over explanatory comments.
- Complex logic must have a single source of truth. Never copy a calculation or business rule into another file or surface.
- Remove dead code, unused state, obsolete compatibility paths, and temporary diagnostics before finishing.
- Do not add compatibility code for OS versions or architectures Palmier Pro does not support.

## Concurrency and the main actor

- Treat the main actor as a scarce UI resource. It may own UI state and lightweight coordination state, but it must not perform file I/O, media decoding, model inference, image processing, indexing, export work, blocking framework calls, or large collection transforms.
- `@MainActor` provides isolation, not performance. Move expensive work out of a main-actor type instead of assuming an `async` method makes it safe.
- `Task {}` inherits actor isolation. Never use it as evidence that synchronous work moved off the main actor.
- `nonisolated` on a synchronous function does not switch threads. A call from the main thread still runs on the main thread.
- Make executor changes explicit. Prefer an asynchronous system API; otherwise use a dedicated utility queue or service, an `@concurrent` async function, or a carefully bounded `Task.detached` over immutable `Sendable` snapshots.
- Snapshot the minimum immutable input before leaving an actor. Return a value, then apply it on the owning actor after checking cancellation and confirming the result is still current.
- At every `await`, assume actor-isolated state may have changed. Revalidate identity, generation, configuration, selection, lifecycle state, and preconditions before committing a result.
- Prefer structured concurrency. Unstructured tasks must have a clear owner, stored handle when cancellation matters, and teardown behavior.
- Cancellation is cooperative. Long operations and loops must check cancellation at useful boundaries, and cancellation must not commit partial or stale results.
- Bound parallel work according to the actual scarce resource. Do not create one task per asset, frame, thumbnail, decoder, or model request without a concurrency limit.
- Deduplicate identical in-flight work where multiple callers can request the same result.
- Actors protect their own state only. Audit process-global state, C/C++ libraries, Metal resources, AVFoundation objects, caches, and third-party dependencies before allowing separate actors to call them concurrently.
- Acquire and release gates in matched scopes. Install `defer` only after acquisition succeeds. Make cancellation while waiting safe.
- Keep continuation state in one isolation domain and resume every continuation exactly once on success, failure, or cancellation.
- Never block the main thread with `DispatchQueue.sync`, semaphore waits, group waits, locks, polling, or synchronous waits for async work.
- Treat Objective-C and third-party callback isolation as untrusted unless documented. Hop explicitly to the correct actor and use `@Sendable` where a callback crosses isolation.
- Avoid `nonisolated(unsafe)` and unchecked `Sendable`. Any use requires a concrete invariant and targeted coverage.

## File I/O and project packages

- Every filesystem operation must execute off the main actor and main thread. This includes reads, writes, encoding to or decoding from disk, existence checks, metadata and resource-value queries, directory enumeration, coordination, copying, moving, replacing, deleting, and directory creation.
- Assume every volume can be slow, removable, externally modified, or network-backed. File size and a successful previous access do not make synchronous main-thread access safe.
- Prefer asynchronous APIs. Run synchronous Foundation file APIs behind an explicit background boundary, preferably a dedicated serial utility queue for coordinated operations.
- The synchronous `FileIO` helpers do not provide an execution hop. Callers are responsible for invoking them from an off-main context.
- Snapshot actor-owned model data before file work. Do not capture a main-actor model or mutate observable state from the file-I/O executor.
- Stage complete output outside the live project package, prepare replacements on the destination volume, and atomically install the finished item.
- Route all live `.palmier` package media installs and removals through `ProjectPackageCoordinator`. Do not write directly into a live package from feature code.
- Serialize operations that target the same package or destination. A save, import, generation result, thumbnail, removal, export, and close operation must not race each other.
- Closing, Save As, and app termination must wait for admitted mutations, reject late commits, and preserve the latest successful state.
- Use unique temporary paths and clean them on success, failure, and cancellation. Never delete or replace a destination until the complete replacement is ready.
- Surface user-requested file failures. Do not hide them with `try?`, empty results, or success-shaped responses.

## Performance

- Treat rendering, playback, scrubbing, audio metering, timeline input, SwiftUI view updates, import, indexing, restore, save, and export as performance-sensitive paths.
- Do not perform filesystem access, logging, JSON encoding, model setup, decoder or reader creation, audio-graph setup, LUT parsing, `CIContext` creation, or other blocking setup inside per-frame, per-sample, per-grain, per-item view, or repeated interaction paths.
- Measure before claiming a performance improvement. Use the relevant Instruments template, signposts, a focused benchmark, or a performance test, then compare before and after under the same workload.
- Fix algorithmic complexity and unnecessary work before applying low-level optimizations. Watch for nested scans, repeated sorting, copy-on-write mutation in loops, intermediate arrays, repeated actor hops, and repeated observation invalidation.
- Batch and coalesce bulk mutations. Preserve explicit consistency boundaries by flushing pending state before save snapshots, undo snapshots, export, close, and reads that promise current data.
- Load and hydrate media lazily. Do not decode thumbnails, waveforms, filmstrips, metadata, transcripts, or models until a consumer needs them.
- Cache expensive reusable work only with an explicit key, capacity, invalidation rule, replacement rule, lifecycle behavior, and stale-result policy.
- Reuse expensive AVFoundation, Core Image, Metal, audio, and model objects when their documented lifecycle permits it. Invalidate them on relevant configuration and application lifecycle changes.
- Keep high-frequency observable state as narrow as possible. A progress counter, meter, or playhead update must not invalidate an entire panel or large media grid.
- Keep SwiftUI `body` work fast and side-effect free. Precompute expensive derived data and observe the smallest state surface that can render the result.
- Limit retained media and cache memory. Use bounded caches, release temporary buffers promptly, and use scoped autorelease pools for large Objective-C media loops when profiling shows retained temporaries.
- Keep per-item success logging out of release hot paths. Production logs should preserve actionable warnings, failures, and batch summaries without evaluating verbose messages unnecessarily.

## Correctness and edge cases

- “Works on the happy path” is not sufficient. Before implementing, enumerate the applicable boundary, lifecycle, concurrency, and failure cases and decide which layer owns each behavior.
- Validate empty, nil, zero, negative, maximum, overflowing, non-finite, malformed, duplicated, missing, stale, and unsupported inputs as applicable.
- Validate before integer arithmetic, frame addition, duration multiplication, indexing, or numeric conversion. Never rely on a later `do`/`catch` to catch a Swift arithmetic trap.
- Define exact rounding and clamping behavior. Do not silently clamp an invalid request unless tolerance is an intentional documented part of the contract.
- Cover no-op and repeated operations. They must report accurately and must not create mutations, undo entries, duplicate work, or misleading success.
- Consider cancellation before start, during each phase, after work completes but before commit, and while waiting for a gate or callback.
- Consider stale completion after selection, timeline, project, asset URL, model, mix, generation, or configuration changes.
- Consider close, quit, sleep, wake, app deactivation, device changes, Save As, and teardown while work is active.
- Consider empty timelines, zero-duration media, missing tracks, corrupt or offline media, variable frame rates, non-integer speeds, time-scale conversion, and long-duration projects.
- Consider linked clips, nested timelines, multicam groups, locked or sync-locked tracks, split clips, overlapping clips, and changes to a child timeline after a carrier was created.
- Consider interaction combinations: keyboard modifiers, Escape, dismissal, mouse-up after cancellation, disabled controls, focus changes, selection changes, and overlapping gestures.
- Consider partial filesystem failure, permissions, an existing destination, identical source and destination, external changes, low space, and cleanup failure.
- Preserve project invariants on every failure path. Partial success must either be safely resumable and reported as such or rolled back.

## Editor mutations and undo

- Route UI and Agent edits through the same domain mutation operations and shared `EditorUndo` history.
- One coherent user intent should produce one undoable action. Do not expose internal substeps as separate undo entries unless they are independently meaningful to the user.
- Validate arguments and preconditions before opening an undo group. Failed, cancelled, refused, and unchanged operations must not create empty undo steps.
- Nested implementation work must coalesce into the outer user action without closing groups owned by AppKit or another subsystem.
- Undo must restore exact state without cumulative frame rounding, derived-state drift, orphaned linked clips, or stale selection.
- Test interleaving between UI edits, Agent edits, automatic AppKit event grouping, project switching, and concurrent tool requests when the change touches undo.

## Agent tool design

- Design tools from user intent, not from internal APIs, database operations, view models, or service method boundaries.
- Start with representative user requests and define the desired outcome, success criteria, warnings, failure behavior, cancellation behavior, retry behavior, idempotency, and undo semantics before defining the schema.
- A tool should perform one coherent filmmaker action. One call should normally complete one atomic, understandable, and undoable workflow.
- Do not force the Agent to reproduce application orchestration by chaining low-level tools when Palmier Pro can safely perform the workflow itself.
- Do not create a broad “god tool” with unrelated modes. Group operations only when they share one user goal, validation model, and result shape.
- Express parameters in filmmaking and user-facing domain concepts. Hide storage layout, framework objects, UI state, and incidental implementation details.
- Use stable entity IDs for automation. Positional indexes and display labels may be returned for context but must not be the only durable identity after edits.
- Treat every tool argument as untrusted. Require exact types, finite numbers, explicit bounds, valid identifiers, and supported combinations before mutation or arithmetic.
- Resolve and validate the full request before mutating state. Apply multi-entity changes atomically and preserve all editor invariants.
- Reuse the same domain operation as the UI. Agent tools must not duplicate timeline math, placement, linking, sync, media, export, or project logic.
- Return structured receipts describing what changed, stable IDs, explicit no-op state, warnings, skipped items, and actionable errors. Do not return a success-shaped response when the requested outcome was adjusted or not achieved.
- Do not silently clamp, retarget, reorder, fall back, or select a different entity unless the tool contract explicitly promises that behavior and reports it.
- Long-running tools must expose a durable job or terminal result that the Agent can inspect. Asynchronous failure must not disappear after the initiating call returns.
- Keep Agent and MCP protocol values stable and machine-facing. Localize UI copy separately; do not serialize localized labels, errors, statuses, or undo names into tool contracts.
- Tool descriptions must explain when and why to use the tool, important constraints, and interactions with other tools. Do not merely rest

... [truncated — full content at source]
Share on X

こちらもおすすめ

Frontend カテゴリの他のルール

もっとルールを探す

CLAUDE.md、.cursorrules、AGENTS.md、Image Prompts の全 302 ルールをチェック。