Skip to content

Projects

A project bundles a folder with its defaults. One project = 1 folder + defaults + pinned sessions + a display name and icon. Sessions belong to a project; the project's folder is the cwd the agent subprocess runs in.

The agent runs as a subprocess; the project's folder is the cwd it gets. Whatever you (or the agent itself, via Bash) put in the folder is the agent's world.

Source

Code: internal/agents/project/project.go (Meta, CRUD, ResolvePath). Migration from the old workspace model: internal/agents/project/migrate.go. Layout math: internal/agents/config/layout.go.

Renamed from "Workspace"

Projects replace the old Workspace concept (familiar term from Codex/Claude). On first boot after upgrade, every existing workspace is migrated 1:1 into a project with the same folder + defaults, and sessions are re-linked automatically — no data loss. The old workspaces/ directory is kept on disk as a defensive backup.

Two kinds: managed vs custom

KindWhere the files liveCreated byWick deletes on project delete?
Managed~/.<app>/agents/projects/<id>/files/Wick (MkdirAll at create time) — empty folderYes
Custom pathAny absolute path you point at (e.g. D:/code/myproject, ~/scratch)You (must already exist before you create the project)No — wick never owned it, wick never deletes it

The custom-path requirement that the directory must already exist is enforced at create time — typos surface immediately, not at first spawn.

A project can hold zero, one, or many repos. There's no git worktree, no auto-clone, no master-branch model. The agent does the cloning itself via Bash if you ask it to.

The folder is part of the project's identity: there's no multi-folder project. Want a different folder? Create another project, or move the session to one.

Built-in default project

Every fresh install has a project named default. It's created by EnsureDefault at boot, can't be deleted, and is what the pool falls back to when a session doesn't specify a project and no other default is configured.

This is what makes "first-message-creates-session" work without any pre-setup: a fresh install + a Slack message in a thread = a session bound to default, agent spawned in ~/.<app>/agents/projects/<default-id>/files/.

Defaults

Each project carries defaults that new sessions inherit when you don't override them per-session:

DefaultEffect
PresetPreset bound at session-create time. Falls back to default.
ProviderProvider type (claude / codex / gemini, or type/name) used when a session doesn't specify one.
System prompt addonFree-text appended to the preset's system prompt for every session in this project.

In the New Session composer, picking a project pre-fills the provider + preset from these defaults (shown as green "inherited" dropdowns); you can still override any of them per session.

Web UI

Projects live in the left sidebar — there's no separate list page. The PROJECTS section lists every project with its session count; clicking one opens the project (a Claude-style landing: compose box on top, the project's chats below). Hover a row to reveal a 📌 pin toggle.

  • + New (sidebar) → /tools/agents/projects/new — the create page.
  • ⚙ Settings (on a project's landing) → /tools/agents/projects/<id> — the full settings page: icon + name, folder (managed/custom radio), defaults, pinned sessions, a meta.json preview, and delete.

The settings form fields:

FieldNotes
IconOne emoji. Optional; defaults to 📁.
NameRequired. Display name (mutable — the id never changes).
FolderRadio: Custom path (absolute, must exist) or Managed (projects/<id>/files/).
Default Preset / ProviderInherited by new sessions.
System prompt addonAppended to the preset system prompt for every session.
DescriptionUI-only metadata.

Pin a project as your default

Each user can pin one project as their personal default (stored in their user metadata, pinned_agent_project_id). When set, opening the Agents tool lands you straight in that project's compose page.

Pin/unpin from the 📌 toggle on the sidebar row or the 📌 Pin as default button on the project landing. One pin per user — pinning another replaces it.

This is distinct from the operator-wide default project (agents.default_project_id in Settings), which is the fallback for channels / API / quick-create when no project is named.

Meta on disk

projects/<id>/meta.json:

json
{
  "id": "01J...",
  "name": "Wick Backend",
  "icon": "📁",
  "description": "Main wick repo work",
  "custom_path": "/d/code/work/wick",
  "defaults": {
    "preset": "engineer",
    "provider": "claude",
    "system_addon": ""
  },
  "pinned_sessions": ["01J..."],
  "tags": [],
  "created_at": "2026-06-01T...",
  "updated_at": "2026-06-01T..."
}

custom_path is omitted for managed projects. Atomic write (tmp file + rename) on every save; updated_at is bumped automatically.

Resolving the cwd at spawn time

The pool calls project.ResolvePath when it's about to spawn an agent:

  1. Session has a project_id set → load that project's meta.
  2. Custom path? Return it as-is.
  3. Managed? Return ~/.<app>/agents/projects/<id>/files/.
  4. Session has no project → pool falls back to cfg.DefaultProjectID (the operator-wide default) → if still nothing → per-session temp dir at sessions/<id>/cwd/.

The pool MkdirAlls managed paths before passing them to exec.Cmd.Dir. Custom paths are assumed to still exist; if you deleted yours out from under wick, spawn surfaces a clean error.

Moving a session between projects

A session stores its binding as meta.project_id. Moving is metadata-only — no filesystem work, the session id and path stay stable so workflows / channels / spawn references don't break. Two ways:

  • Drag a chat row (sidebar or list) onto a project in the sidebar.
  • The Move to project menu on the session detail page.

The new project's folder becomes the cwd at the next spawn. A live subprocess keeps its old cwd until it's killed and respawned. Deleting a project doesn't delete its sessions — they're just unscoped (project_id cleared).

Multi-session sharing

Multiple sessions can share the same project and run in parallel. Wick does not lock — coordination is your concern. Most agent traffic is read, so two sessions touching the same folder is rarely a problem in practice; two sessions both editing package.json is on you.

Slack / Telegram / REST default project

Each channel (Slack, Telegram, REST) has its own project_id config field. When set, every session auto-created from that channel binds to it. When only one project exists, the channel uses it without asking.

The REST (OpenAI-compatible) channel additionally lets a request override the channel default per call with a top-level "project": "<id>" field (or metadata.project / metadata.project_id). See the REST channel docs.

See also

  • Pool & Sessions — how the cwd is actually wired into exec.Cmd.
  • Providers — the provider default on project meta.
  • Channels — per-channel default project config.
Built with ❤️ by a developer, for developers.