Mode d’emploi
- Copiez la commande et examinez le paquet avant de l’installer dans votre environnement agent.
- Consultez le document original pour les outils, identifiants et environnements requis.
- Décrivez les entrées et le livrable souhaité ; comparez la sortie aux sources.
npx skills add https://github.com/midasmatterhorn/artcraft-skills --skill photocraftAvant de commencer
- L’installation n’inclut ni abonnement au modèle, ni quota API, ni accès aux fichiers.
- Étoiles et installations reflètent l’activité, pas un test indépendant de qualité ou de sécurité.
Rendu depuis le dépôt source en conservant titres, exemples, code, tableaux, liens et images.
PhotoCraft
Overview
PhotoCraft is an open-source, native image editor: "Image editing; an open-source, clean-room reimplementation of Adobe Photoshop, rebuilt in pure Rust" (README.md:13), dual-licensed MIT/Apache-2.0, from the storytold org (repo storytold/photocraft). The desktop app is egui/eframe on wgpu with a CPU compositor as the reference oracle; the same Rust compiles to WebAssembly for the browser build (apps/photocraft-web, Cargo.toml wasm-release profile, cargo xtask wasm). Everything user-visible is an engine command, so the UI, photocraft-cli, the JSON control channel and the MCP server run the same code (README.md:221-242, crates/engine/src/commands.rs). Maturity is early alpha: ~76% feature breadth, ~45% "ready for real work", 953 open issues at the last measurement (ROADMAP.md:3-45, docs/target-app-parity.md). The source inspected here is tag v0.10.0 (commit 8407d9ccb125af52944fca9d228383459f94aaef), which is exactly the installed /Applications/PhotoCraft.app 0.10.0.
Capabilities (verified)
Editing core
- Documents and colour: RGB, Grayscale, CMYK and Lab at 8/16/32-bit float, plus Bitmap, Indexed, Duotone and Multichannel; ICC colour management in pure Rust with Assign/Convert to Profile, rendering intents, black point compensation, soft proofing (
view.proofSetup,view.proofColors) and Gamut Warning (README.md:194-199,crates/cms,crates/engine/src/*_cmds.rs). - Layers, done properly: pixel layers, groups, clipping masks, pixel and vector masks, fill layers (solid/gradient/pattern), adjustment layers, live smart objects with smart filters and lossless transforms/warps, alpha channels, Quick Mask, layer comps, artboards (
README.md:188-191,crates/doc,crates/engine,docs/scorecard.mdFILE-215 rows). - 16 adjustment-layer commands:
layer.newAdjustmentLayer.{blackWhite, brightnessContrast, channelMixer, colorBalance, curves, exposure, gradientMap, hueSaturation, invert, levels, photoFilter, posterize, selectiveColor, threshold, vibrance}(grep ofcrates/engine/src/; 16 ids). - 10 layer effects, several instances per kind allowed: DropShadow, InnerShadow, OuterGlow, InnerGlow, Stroke, ColorOverlay, GradientOverlay, PatternOverlay, Satin, BevelEmboss (
crates/doc/src/effects.rs:261). - Blend modes: PassThrough (groups) + 27 Photoshop blend modes + 6 Paint.NET variants (
crates/color/src/blend.rs). - 67 tools including Remove, Spot/Healing Brush, Patch, Content-Aware Move, Mixer Brush, Magnetic Lasso, Object/Quick Selection, Select Subject, Pen/Freeform/Curvature Pen, Convert Point, shapes, Type and Type Mask, Frame, Slice (
crates/ui-egui/src/state.rs:141—pub const ALL: [Tool; 67]). - Selections: marquee/lasso/wand,
select.quick,select.object,select.subject,select.sky,select.colorRange,select.focusArea,select.refineEdge; Select and Mask opens a dialog forselect.refineEdge(crates/engine/src/smartselect_cmds.rs,crates/ui-egui/src/menus.rs:473). - Filters with live in-dialog preview:
crates/engine/src/filters.rs,filters_ext.rs,gallery_cmds.rs; filters on a smart object become re-editable smart filters (README.md:144-150). - Type: point and paragraph text edited on canvas, Character/Paragraph controls,
type.warpText, OpenType features,type.resolveMissingFonts; type on a path is implemented (type.attachToPath/type.detachFromPath,crates/engine/src/type_extra_cmds.rs:695-703) even though older roadmap prose still lists it as missing. - Vectors: Pen/Freeform/Curvature tools, insert/delete/convert anchor, paths panel, work paths, shape layers, path-to-selection; SVG opens as editable shape layers or a vector smart object (
crates/io/src/svg.rs). - Actions: record/replay,
actions.play, Photoshop.atnimport/export mapping ~112 Photoshop events (crates/engine/src/atn_cmds.rs,docs/development.md). - Print: File › Print renders one flattened PDF page and hands off via
lp/CUPS-IPP/portal (file.print,file.printOneCopy,docs/printing.md). - Video-lite:
timeline.createandfile.export.renderVideo(PNG sequence / animated GIF) (crates/engine/src/timeline_cmds.rs:137,video_cmds.rs:406).
Files — read / write
- Native:
.pcraft(zip of STORE entries or a directory) =manifest.json(format version 1, migrations incrates/format/src/migrate.rs) + content-addressed BLAKE3/zstdtiles/andblobs/+thumb.png+composite/preview.png; incremental saves, atomic writes, crash-recovery autosaves (crates/format/src/lib.rs:3-19,crates/format/src/autosave.rs). Registered macOS typeai.storyteller.photocraft.document(bundle Info.plist). - Read + write: PSD and PSB (layers, groups, masks, vector masks, adjustment and fill layers, effects, text, shapes, smart objects, alpha channels; streaming) —
crates/io/src/psd_import.rs,psd_export.rs,crates/psd; OpenRaster.orawith layers/groups/blend modes —crates/io/src/ora.rs; layered TIFF (Photoshop layer data, both byte orders; extra alpha channels and a Quick Mask are not written) —crates/io/src/tiff_layers.rs; and viaphotocraft-codecs: PNG (8/16-bit), JPEG, TIFF (8/16/32f, BigTIFF), WebP (lossless + own lossy VP8 encoder), GIF, BMP, TGA, ICO, Netpbm (PBM/PGM/PPM/PAM/PFM), QOI, OpenEXR (f16/f32), Radiance HDR, FITS, DPX (8/10/12/16-bit) (crates/codecs/README.mdcapability matrix; export dispatchcrates/io/src/lib.rs:390-452). - Read-only imports: Paint.NET PDN3 (editable layers, 14 blend modes), Krita
.kra/.krz, Affinity.af/.afdesign/.afphoto/.afpub, DDS textures, Cineon, SVG (as shape layers), HEIC/HEIF (official builds enable theheiffeature), and camera raws —crates/io/src/pdn.rs,kra.rs,affinity.rs,svg.rs,crates/codecs/README.md,crates/raw/src/lib.rs:31-37. - Camera raw decode: DNG (uncompressed, deflate, lossless-JPEG, lossy-JPEG and JPEG XL, CFA and LinearRaw), CR2, TIFF/EP raws (NEF, ARW, PEF), Nikon compressed NEF, Sony cRAW, Panasonic RW2, uncompressed Olympus ORF, uncompressed Fujifilm RAF (Bayer and X-Trans); everything else reports Unsupported, and CR3 gives only its embedded JPEG preview + orientation, not sensor data (
crates/raw/src/lib.rs:31-37,241,cr3.rs). - PDF: write only, one flattened RGB/Gray/CMYK page with ICC — Save As / Save a Copy / CLI and print (
crates/io/src/pdf.rs:8,docs/file-format-parity.mdFILE-215-10). - Export As formats:
png,jpg,webp,tif,tga,ico(crates/engine/src/export_preset_cmds.rs:13). Save for Web:gif,png8,png24,jpeg,wbmp(crates/engine/src/web_cmds.rs:46-59). Quick Export as PNG (crates/engine/src/shell_commands.rs). - Depth honesty:
caps(format)andfidelity_warningsreport what an export will lose before it is written; CLI and desktop surface those as warnings (crates/codecs/README.md).
Automation surfaces
- One command registry: every Photoshop menu item in the catalog is wired — 631/631 live, enforced by
FLOOR = 631(crates/ui-egui/src/parity.rs:10,docs/parity-checklist.md). Wiring is not behaviour; checkenabled/disabledReason/needsDocumentper command (docs/control-protocol.md). - CLI `photocraft-cli` — 8 subcommands, all flags enforced (an unknown flag is a usage error, exit 2):
convert,info,run,batch,droplet,commands,mcp,serve(apps/photocraft-cli/src/lib.rs:14-100). - Control channel:
photocraft --control <port>serves authenticated JSON lines on127.0.0.1only; first frame must be{"id":"auth","method":"auth","params":{"token":"<64 hex>"}}; 60-second reply timeout. Methods includeengine.execute,engine.commands,ui.inspect,ui.set,ui.menu.invoke/list,ui.pointer,ui.click,ui.move,ui.key,ui.type,ui.dialog.*,ui.screenshot,ui.window.open/close,app.open,app.save,app.quit(docs/control-protocol.md,apps/photocraft/src/control_server.rs,crates/ui-egui/src/control.rs). - MCP:
photocraft-cli mcpruns headless;--bridge 127.0.0.1:<port>wraps a running app. Tools:command_list,command_run,command_batch,doc_inspect,render_preview,ui_inspect,ui_screenshot(+ session/job tools); resourcesphotocraft://document,photocraft://commands(docs/mcp.md). - Headless server:
photocraft-cli serve(stdio or--port) answersdoc.open/new/place/save/exportLayers/exportDataSets/importDataSets/inspect/render/select/close,engine.execute,batch,session.list,jobs.list/cancel(apps/photocraft-cli/src/lib.rs:46-51). - Plug-ins: WebAssembly ABI v1 —
plugin.install/run/remove/reload/list, wasmi sandbox, no WASI/filesystem/network, 50M-instruction fuel and 60 s budget per run (docs/plugins.md). - Batch/droplets:
photocraft-cli batchapplies an actions JSON, an Actions set, or a.atnfile to a folder;.pcdropletdroplets run viafile.automate.runDropletwith a Unix.commandshim (crates/engine/src/automate_cmds.rs:313-566). MCP acceptance: 10 scripted agent tasks + more incrates/automation/tests/agent_tasks.rs,agent_tasks_more.rs.
Platform
- macOS, Windows, Linux, FreeBSD natives and a WebAssembly web build (
README.mdDownloads;Cargo.tomlwasm-release;cargo xtask wasm). - GPU compositor on wgpu (Metal/Vulkan/DX12/WebGPU) with CPU fallback,
--safe-gpu, automatic driver-crash fallback andui.gpu.simulateLossfor testing (apps/photocraft/src/gpu_startup.rs,docs/control-protocol.md). - Pen tablets: pressure/tilt/rotation on macOS (isolated AppKit monitor crate), Windows (
WM_POINTERvia winit), Linux X11 (XInput2), web (Pointer Events); Wayland native tablet-v2 still open (AGENTS.md,crates/tablet,docs/roadmap.mdM6).
Known limitations and not-implemented
Read this before assigning work — several of these are the reason agents should not promise Photoshop behaviour.
- Alpha, by measurement: ~45% "ready for real work" and 953 open issues at last count (
ROADMAP.md:42-47); the committed performance baseline has 3 of 58 scenarios within budget, 22 over budget or failing (including a GPU validation crash at 150 layers, P12), 24 not yet measured or tracked (docs/scorecard.mdPerformance). - PSD fidelity is the blocking gap (G1): enforced corpus floors are minimums — Photoshop-authored oracles 188/256 render-pass with 258 round trips, psd-tools 249/309, io corpus 148/170 (
crates/io/tests/corpus.rs:151-159,docs/scorecard.md). A re-saved PSD is not byte-identical to its source (README PSD section), and there is no test that a third-party editor re-opens our exports (FILE-216-4, missing). User reports of Photoshop refusing our files exist (#1281, #2469;docs/gaps.mdG1). - No AI/generative features: no
mlcrate in the workspace;docs/roadmap.mdM10 says "ML backend not started"; the code deliberately declines Generative Expand (crates/ui-egui/src/panels.rs:1309). No Neural Filters, no generative fill/expand, no sky replacement ML. - No native Photoshop plug-ins:
.8BF, CEP and UXP are not hosted; only the Wasm plug-in ABI (docs/plugins.md). - Missing tool: Art History Brush — 1 of Photoshop's 68 (
docs/gaps.mdG6;crates/ui-egui/src/state.rs:141). - Workspaces that are dialogs, not workspaces (G7): Select and Mask opens a filter dialog (
crates/ui-egui/src/menus.rs:473); no Content-Aware Fill sampling workspace, no Vanishing Point plane editor. - Formats absent or partial: no PDF import (#2541); AVIF read missing and AVIF write only behind the non-default
avifbuild feature; JPEG XL, JP2, DICOM, PCX, PICT, Scitex CT, Photoshop Raw and Cloud PSD unsupported (crates/codecs/README.md,docs/file-format-parity.md). Affinity and Krita are import-only; PDN is import-only (crates/io/src/lib.rs:392-400). GIF opens first-frame-only (use New Video Layer from File for frames); APNG keeps the first frame; per-frame delays are not persisted (docs/file-format-parity.md). - Camera raw partial: unsupported variants fall back to the embedded JPEG preview; "lossy after split" NEF no; no
.xmpsidecars; CR3 sensor data no (crates/raw/src/lib.rs,docs/file-format-parity.md). - Dead preferences: 26 of 168 settings do nothing (
docs/scorecard.md). - Localization: UI strings are translated (10+ languages) but engine messages stay English; Hindi, Arabic and Vietnamese are 0% (
ROADMAP.md). - Windows: PSB files over 4 GB fail (#375).
- Wayland: no drag-and-drop (winit 0.30 limit) and XWayland fractional scaling is blurred (
README.md:282). - Timeline/video and HDR are early, and the plug-in/scripting ecosystem is thin (
docs/roadmap.mdM12 "print, HDR, timeline pending";docs/gaps.mdG16 plug-in compatibility and scripting). - Docs lag code between releases (the roadmap still carries pre-0.10 numbers; the scorecard regenerates). Verify against the installed version before asserting a feature is missing.
How to operate
Launch (macOS)
open -a PhotoCraft # normal GUI launch
open -a PhotoCraft /path/to/file.psd # open a file in the running instance
open -a PhotoCraft --args --control 7878 --control-token-file "$HOME/.photocraft/control.token" \
--automation-read-root "$PWD" --automation-write-root "$PWD"- Binary:
/Applications/PhotoCraft.app/Contents/MacOS/PhotoCraft; the app bundle contains no CLI — getphotocraft-clifrom the release zip (photocraft-cli-<ver>-macos-universal.zip, signed and notarized) or build it. - App options (verified in
apps/photocraft/src/main.rs:168-198):-h/--help,--version,--safe-gpu,--in-window-menus,--new-instance,--present-mode <fifo|autovsync|novsync>,--frame-latency <1..3>,--stroke-trace <stderr|file.csv>,--control <port>,--control-token <64-hex>,--control-token-file <path>,--automation-read-root <dir>,--automation-write-root <dir>,--. Env equivalents exist (PHOTOCRAFT_CONTROL_PORT,PHOTOCRAFT_CONTROL_TOKEN, …,PHOTOCRAFT_CONFIG_DIR). - If no token is given, a fresh one is generated and printed to stderr; a token file is created with mode 0600. Treat it as a credential.
- Do not launch the GUI just to inspect a file: use the CLI (below). macOS does not render occluded windows, so live screenshots steal focus (
ui.screenshotraises the window by default;docs/development.md).
Headless CLI
Build or run from source: cargo run -p photocraft-cli -- <subcommand> (or cargo build --release -p photocraft-cli).
photocraft-cli convert in.psd out.pcraft [--format <ext>] [--quality 1-100] [--tiff-layers] [--tga-bits 24|32] [--dpx-bits 8|10|12|16]
photocraft-cli info out.pcraft [--compact] # JSON: size, mode, depth, layer tree, warnings
photocraft-cli run in.png --cmd layer.new.layer --params '{"name":"Ink"}' \
--cmd filter.blur.gaussianBlur --params '{"radius":3}' \
--out out.psd [--format <ext>] [--quality 1-100] [--tiff-layers]
photocraft-cli run --new '{"width":800,"height":600,"background":"white"}' --cmd document.inspect --out new.pcraft
photocraft-cli batch --actions actions.json [--action <name>] --in ./raw --out ./graded [--format jpg] [--in-place]
photocraft-cli droplet job.pcdroplet ./images [--out ./done]
photocraft-cli commands [--json] [--filter blur]
photocraft-cli mcp [--bridge 127.0.0.1:7878] [--control-token-file <path>] \
[--automation-read-root <dir>] [--automation-write-root <dir>]
photocraft-cli serve [--port <port>] [--control-token-file <path>] [--automation-read-root <dir>] [--automation-write-root <dir>]Behaviour that bites: each --params must follow its --cmd; run needs exactly one of <file> or --new <json>; every command's JSON result is one line on stdout while warnings go to stderr; exit codes are 0 ok / 1 failure / 2 usage; batch refuses an --out equal to --in unless --in-place, and refuses to overwrite a same-named output; --quality on convert means JPEG and lossy WebP (without it WebP is lossless) (apps/photocraft-cli/src/lib.rs).
Document and window model
One window holds the open documents as tabs (the control channel exposes them as window.document.<index> in tab order); ui.window.open adds an extra window for a document. On Windows and Linux a second launch hands its files to the running instance as new tabs; --new-instance and any --control launch start a separate process (macOS relies on LaunchServices). (apps/photocraft/src/main.rs:13-15, docs/control-protocol.md.)
Open / save / export flow
- Open: File › Open (
Cmd+O), drag-and-drop, orphotocraft-cli. Save (Cmd+S) writes back to the document's own.psd,.psbor.pcraft; Save As (Cmd+Shift+S) picks the format from the file extension —.pcraftfor the lossless native bundle, PSD/PSB for Photoshop handoff, any writable codec extension for flat output, and.pdfwrites one flattened page. - Over the control channel or MCP use
app.open/app.savewith paths relative to the automation roots —file.open,file.openAs,file.save,file.saveAs,file.saveACopy,file.export.saveForWebLegacy,pattern.importand smart-object file commands are refused by automation (crates/automation/src/workspace.rs:683-702). - Export As (
Cmd+Alt+Shift+W) offers png/jpg/webp/tif/tga/ico; Save for Web offers gif/png8/png24/jpeg/wbmp; Quick Export as PNG is one menu item away (crates/engine/src/export_preset_cmds.rs:13,web_cmds.rs:46-59,shell_commands.rs). - Keyboard shortcuts: the authoritative tables are
crates/engine/src/shell_commands.rs(shell + tool defaults) andcrates/ui-egui/src/menu_catalog.rs(menu items). Verified examples:Cmd+FSearch…,Cmd+JLayer via Copy,Cmd+DDeselect,Cmd+O/Cmd+S/Cmd+Shift+S,Cmd+Alt+Shift+WExport As,F7Layers,F6Color,F5Brush Settings. Photoshop shortcut sets import/export throughedit.keyboardShortcuts(.kys).
State on disk
- macOS settings dir:
~/Library/Application Support/Photocraft/—preferences.json,Presets/,ui.ron, and crash recovery next to it inRecovery/. Override withPHOTOCRAFT_CONFIG_DIR; portable mode (aportable.txtorPhotoCraft.portablemarker beside the executable) keeps everything in<exe dir>/PhotoCraftData/(apps/photocraft/src/app_dirs.rs). - Recovery autosaves are
<Recovery>/<key>.pcraftdirectory bundles plus<key>.jsonmetadata; the entry is deleted only when the document is saved or closed, and recovery is offered at the next launch (Preferences › File Handling › Recover on launch). Autosave interval: preferencefileHandling.autosaveMinutes, default 10, valid 1–240 (crates/format/src/autosave.rs,crates/engine/src/prefs.rs:439-470,1108).
Working with an AI agent
Preferred ladder — use the highest rung that answers the question:
- Headless CLI for convert/inspect/batch; it needs no GUI and no token.
- MCP headless (
photocraft-cli mcp --automation-read-root … --automation-write-root …) when the task is a sequence of engine commands with inspection; without roots it has no file authority (by design). - Control channel on a live app when UI state, dialogs, pointer gestures or screenshots are genuinely required.
- GUI pointer events last —
ui.pointer/ui.keyare validated and replayable, but they depend on window focus on macOS.
Legitimate work:
- Prepare inputs: convert any supported source to
.pcraft/PSD/PNG, resize/grade viabatch, generate actions JSON or droplets, pre-export assets for other Craft apps. - Read and interpret documents:
photocraft-cli info <file>JSON (size, mode, depth, layer tree, warnings) ordocument.inspect,layer.list,document.pixelover MCP/control..pcraftmanifest.jsonis plain JSON and can be read directly. - Verify exports: reopen with
photocraft-cli info, read stderr warnings, probe pixels (document.pixel), compare size/alpha. Do not byte-compare a re-saved PSD to its source: PhotoCraft rewrites image resources, layer records and the composite on save (unknown PSD blocks are carried through verbatim), so only reopening the file tells you it is right. - Repair by regeneration, not by hand:
.pcrafttiles/blobs are content-addressed (BLAKE3) zstd objects — never edit them in place. Rebuild from the source image, an earlier bundle, or the app: a bundle written by a newer format version is refused with a clear error (crates/format/src/lib.rs:58,migrate.rs). - Batch safely:
batchwill not silently overwrite; MCPcommand_batchis not atomic (earlier steps stay applied), so inspect history afterwards and undo per history entry.
Do not: assign the app AI/generative work, expect Photoshop to always open its PSD exports, assume a format is supported because Photoshop has it, drive the GUI blind when a headless command exists, run two instances that share one recovery folder, apply whole-Preferences updates over the control channel (change individual keys with prefs.set), or rely on doc statements that the code contradicts (docs lag by weeks — trust the source).
Verification protocol
PhotoCraft is alpha: verify every artefact, never trust a silent export.
- Round-trip smoke test before trusting any output:
photocraft-cli run --new '{"width":64,"height":64,"background":"white"}' --cmd layer.new.layer --out /tmp/t.pcraft then photocraft-cli info /tmp/t.pcraft, then photocraft-cli convert /tmp/t.pcraft /tmp/t.png and open /tmp/t.png in another viewer. For edits, add a command between --new and --out and read the per-command JSON lines.
- Read warnings. Fidelity warnings (bit-depth reduction, CMYK→RGB, dropped layers, missing fonts) print to stderr on
convert/run/batchand appear ininfo/app.savewarnings. An export without a warning is the only export you should believe. - Version projects. Keep the
.pcraftfor lossless re-edits and hand Photoshop the PSD/PSB; keep the original source. PhotoCraft's re-saved PSD is not byte-identical and older/newer formats migrate on load. - Update only between projects. The app updates through the ArtCraft Launcher; a version bump can change how files save. This skill documents 0.10.0 (
v0.10.0, HEAD8407d9c); if the installed app differs, re-verify format and command claims against the new build (photocraft --versionprints version, commit and build date). - Prefer reversible operations. Work on copies (
image.duplicateorhistory.newDocumentcreates a new active document), inspectdocument.inspecthistory, and remember automation saves never fire script events.
Sources & evidence
- Repo: https://github.com/storytold/photocraft — inspected at tag
v0.10.0, HEAD commit8407d9ccb125af52944fca9d228383459f94aaef(2026-10-17); date of inspection 2026-10-18. - Installed app:
/Applications/PhotoCraft.app—CFBundleShortVersionString0.10.0, bundle idai.storyteller.photocraft, minimum macOS 11.0 (read fromContents/Info.plist; the app was not launched). - Key files read:
README.md,ROADMAP.md,Cargo.toml,AGENTS.md,apps/photocraft/src/main.rs,apps/photocraft/src/app_dirs.rs,apps/photocraft-cli/src/lib.rs,crates/format/src/lib.rs,crates/format/src/autosave.rs,crates/io/src/lib.rs,crates/io/tests/corpus.rs,crates/codecs/README.md,crates/raw/src/lib.rs,crates/doc/src/effects.rs,crates/color/src/blend.rs,crates/ui-egui/src/state.rs,crates/ui-egui/src/parity.rs,crates/ui-egui/src/menus.rs,crates/engine/src/commands.rs,crates/engine/src/type_extra_cmds.rs,crates/engine/src/export_preset_cmds.rs,crates/automation/src/workspace.rs,crates/automation/tests/agent_tasks.rs,docs/control-protocol.md,docs/mcp.md,docs/scorecard.md,docs/gaps.md,docs/roadmap.md,docs/development.md,docs/file-format-parity.md,docs/parity-checklist.md,docs/plugins.md,docs/printing.md. - Shared libraries:
storytold/craft-libs(pinned by git revision inCargo.toml:craft-ui,craft-print,craft-docpath); consulted only to confirm it is a pinned external dependency here, not for app behaviour.

