diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts
index ad440acd..7919769d 100644
--- a/docs/.vitepress/config.ts
+++ b/docs/.vitepress/config.ts
@@ -412,7 +412,7 @@ if(n<200&&document.readyState==="loading")requestAnimationFrame(function(){bar(n
},
],
},
- { text: "Workspace Audit logs", link: "/workspaces-and-users/audit-logs" },
+ { text: "Workspace Audit Logs", link: "/workspaces-and-users/audit-logs" },
{
text: "Billing and plans",
collapsed: true,
@@ -456,6 +456,8 @@ if(n<200&&document.readyState==="loading")requestAnimationFrame(function(){bar(n
{ text: "Publish projects", link: "/core-concepts/deploy" },
],
},
+ { text: "Project Audit Logs", link: "/projects/project-audit-logs" },
+
{
text: "Project States",
link: "/core-concepts/projects/project-states",
@@ -539,9 +541,13 @@ if(n<200&&document.readyState==="loading")requestAnimationFrame(function(){bar(n
link: "/core-concepts/projects/milestones",
},
{
- text: "Releases",
+ text: "Workspace Releases",
link: "/releases",
},
+ {
+ text: "Project Releases",
+ link: "/projects/releases",
+ },
{ text: "Stickies", link: "/core-concepts/stickies" },
],
},
@@ -595,6 +601,7 @@ if(n<200&&document.readyState==="loading")requestAnimationFrame(function(){bar(n
],
},
{ text: "Page Templates", link: "/templates/page-templates" },
+ { text: "Edit MS Office Files", link: "/pages/edit-ms-office-files" },
],
},
{
@@ -734,6 +741,7 @@ if(n<200&&document.readyState==="loading")requestAnimationFrame(function(){bar(n
items: [
{ text: "Plane AI", link: "/ai/plane-ai" },
{ text: "AI Skills", link: "/ai/ai-skills" },
+ { text: "AI Usage", link: "/ai/ai-usage" },
{ text: "AI credits", link: "/ai/plane-ai-credits" },
{ text: "MCP Connectors", link: "/ai/mcp-connectors" },
{
diff --git a/docs/ai/ai-usage.md b/docs/ai/ai-usage.md
new file mode 100644
index 00000000..7b640410
--- /dev/null
+++ b/docs/ai/ai-usage.md
@@ -0,0 +1,70 @@
+---
+title: AI usage
+description: Monitor how much Plane AI your workspace and its members consume each month, view usage trends and breakdowns, and understand your monthly allowance and limits.
+---
+
+# AI usage
+
+AI usage shows how much Plane AI your workspace consumes. It gives you a monthly meter, a usage trend over time, and a detailed breakdown of where AI is being used, so you can keep an eye on consumption and stay ahead of your monthly allowance.
+
+AI usage is read-only. It reports consumption, and it does not change any settings or data.
+
+## Where to find it
+
+Open Plane AI and use the sidebar to reach two screens:
+
+- **Usage** shows your monthly meter and usage trend.
+- **Analytics** shows a detailed breakdown of consumption.
+
+## Personal and workspace views
+
+Both screens have a **Personal** and a **Workspace** view:
+
+- **Personal** shows your own AI consumption. Any member can see this.
+- **Workspace** shows consumption across the whole workspace, including every member and any AI agents. Only **Admins** and **Owners** can see the Workspace view.
+
+## The Usage screen
+
+**Monthly meter.** A meter shows how much of your monthly allowance has been used in the current period. On Plane Cloud this is shown as a **percentage** of your allowance. The meter can read above 100% because the limit is applied after a request completes, not partway through it.
+
+**Reset date.** Below the meter, Plane shows where you are in the current cycle (for example, the day within the month) and the date the allowance **resets**. Allowances reset monthly.
+
+**Usage trend.** A chart plots consumption over time. You can switch the interval between **Week** and **Month** and move between periods to see how usage is changing.
+
+On self-hosted deployments, usage is measured in **tokens** rather than a percentage, and the Usage screen also shows total **tokens in** and **tokens out**.
+
+## The Analytics screen
+
+The Analytics screen breaks usage down so you can see exactly where AI is being spent. Choose a dimension to group by:
+
+- **Models** — which AI models were used
+- **Users** — consumption per member
+- **Agents** — consumption by AI agents
+- **Features** — which AI features were used (for example chat, page actions, or predictions)
+- **Projects** — consumption per project
+
+The breakdown is a table with the group's name, its **share of usage**, the **tokens used**, and the number of **requests**. The table is paginated, and you can **export** it to CSV for offline analysis.
+
+The Users, Agents, and Projects breakdowns are part of the Workspace view, so they require Admin or Owner access.
+
+## Your monthly allowance and limits
+
+Each workspace has a monthly AI allowance that depends on your plan. Consumption counts against that allowance during the billing month and resets at the start of the next one.
+
+- **Nearing your limit.** When you reach about 80% of your allowance, Plane shows a warning so you can plan ahead.
+- **Reaching your limit.** When the allowance is used up, Plane AI features are **paused** for that subject (a member or the workspace's agents) until the next monthly reset. The request that crosses the limit still finishes; the next one is blocked. You will see a message that AI capabilities are temporarily disabled until the reset date.
+
+Because the limit is applied after a request rather than partway through, your meter can briefly show slightly over 100%.
+
+For how allowances are assigned per plan, what overage does, and how billing works, see [Plane AI credits](/ai/plane-ai-credits).
+
+## Plane Cloud and self-hosted
+
+How usage is measured depends on where Plane runs:
+
+- **On Plane Cloud**, usage is shown as a **percentage** of a monthly allowance that scales with your plan. Members and AI agents each have their own allowance.
+- **On self-hosted deployments**, you connect your own AI provider, so **members are not metered**. Usage is reported in **tokens**, and only the shared pool used by AI agents is bounded, and only if your administrator has configured a token budget for it. If no agent budget is configured, agent features are unavailable rather than metered.
+
+## Availability
+
+AI usage is part of **Plane AI** and appears only where Plane AI is enabled for your workspace. If Plane AI is not enabled, the Usage and Analytics screens are not available. See [Plane AI](/ai/plane-ai) for how to enable it.
diff --git a/docs/ai/plane-ai-credits.md b/docs/ai/plane-ai-credits.md
index 30f19309..64f7a0d5 100644
--- a/docs/ai/plane-ai-credits.md
+++ b/docs/ai/plane-ai-credits.md
@@ -1,70 +1,81 @@
---
title: How Plane AI credits work
-description: Understand seat-based AI credits, what happens when included credits run out, and how workspace overage keeps your team moving.
+description: Understand how Plane AI credits work on Plane Cloud per-seat monthly allowances, what happens when they run out, workspace overage, and how to monitor usage.
---
# Plane AI credits
-Plane AI credits measure AI usage in Plane Cloud.
+Plane AI credits measure how much Plane AI (Pi) your workspace uses on Plane Cloud. Your plan includes a monthly allowance, and AI features draw from it as your team uses them.
-::: warning IMPORTANT
-AI credits apply only to Plane Cloud.
+To see how much of your allowance you have used, open the [AI usage](/ai/ai-usage) dashboard. It shows your consumption for the current month as a percentage of your allowance.
-On self-hosted instances, you use your own AI provider [API key](https://developers.plane.so/self-hosting/govern/instance-admin#artificial-intelligence), and all AI usage and costs are managed directly through your provider.
+::: warning Credits apply only to Plane Cloud
+On self-hosted instances you connect your own AI provider [API key](https://developers.plane.so/self-hosting/govern/instance-admin#artificial-intelligence), so there are no Plane credits. All AI usage and costs are handled directly through your provider, and members are not metered by Plane.
:::
## How credits are assigned
-Credits are included **per paid seat**.
+Credits are included with your plan and refresh every month.
-- Each active seat gets a monthly included credit amount based on your plan.
-- Included credits are account-level entitlements tied to seats.
-- This model is designed to be simple and predictable, similar to how modern AI products commonly package usage.
+- Each active paid seat gets a monthly included allowance based on your plan.
+- The allowance is an entitlement tied to seats, so your total capacity scales with your team.
+- Allowances reset at the start of each monthly billing period.
-For current included amounts by plan, check the latest pricing details on [Plane pricing](https://plane.so/pricing#ai-&-credits).
+AI **agents** draw from a separate, workspace-level allowance rather than from any one member's. Automated agent activity does not consume a person's individual credits.
-## No default pooling
+For current included amounts by plan, see [Plane pricing](https://plane.so/pricing#ai-&-credits).
-Plane AI credits are **not pooled by default**.
+## Credits are not pooled by default
-That means one member's unused included credits are not automatically shared across the rest of the workspace.
+Each member has their own monthly allowance. One member's unused credits are not automatically shared with the rest of the workspace. This keeps each person's available capacity predictable.
-## What happens when included credits run out
+## What happens when credits run out
-If a member (or your workspace's included capacity) runs out of available credits for the billing period, AI usage can stop unless overage is enabled.
+As a member approaches their allowance, at around 80% used, Plane shows a warning so they can plan ahead.
-Workspace admins can enable a workspace-level overage setting so teams can continue using AI after included credits are exhausted.
+When the allowance is fully used for the month, what happens depends on whether workspace overage is enabled:
+
+- **Overage off (the default).** Plane AI features pause for that member until the allowance resets at the start of the next month. The request that reaches the limit still finishes, and the next one is paused. The member sees a message that AI is temporarily unavailable until the reset date.
+- **Overage on.** AI keeps working past the included allowance, and the additional usage is billed at the workspace level.
+
+The same applies to the workspace's agent allowance: agents pause when it is used up, unless overage is enabled.
## Workspace overage
-When workspace overage is enabled:
+Overage is a workspace-level setting that keeps your team moving after included credits are used up.
+
+- When enabled, AI usage continues past the included allowance.
+- The additional usage is billed to the workspace.
+- Workspace admins decide whether to allow it, so cost stays in your control.
-- AI usage continues after included credits are consumed.
-- Additional usage is billed at the workspace level.
-- Admins stay in control of whether overage is allowed.
+If overage is off, AI pauses at the limit until credits reset or more capacity is added to the workspace.
-If overage is disabled, new AI actions are paused after included credits are exhausted until credits reset or additional capacity is purchased/enabled.
+## Monitor usage
-## Tracking and controls
+Track consumption from the [AI usage](/ai/ai-usage) dashboard:
-Plane provides usage visibility so admins can manage cost and adoption:
+- A **monthly meter** shows how much of the allowance has been used, as a percentage.
+- A **usage trend** chart shows how consumption changes over time.
+- An **analytics breakdown** shows where AI is being used, by member, feature, project, model, and agent.
-- Current credit balance and consumption trends
-- Workspace-level usage monitoring
-- Billing visibility for additional usage when overage is enabled
+Every member can see their own usage. Workspace admins and owners can also see workspace-wide usage.
## FAQs
::: details Are credits shared automatically across all users in my workspace?
-No. Plane does not use automatic credit pooling by default.
+No. Credits are not pooled by default. Each member has their own monthly allowance.
:::
::: details Do I get credits for each seat?
-Yes. Included credits are assigned per paid seat based on your plan.
+Yes. An included allowance is assigned per paid seat based on your plan. AI agents draw from a separate, workspace-level allowance.
:::
::: details Can we keep using AI after included credits are used up?
-Yes, if a workspace admin enables overage at the workspace level.
+Yes, if a workspace admin enables overage. Otherwise, AI pauses for that member until the allowance resets at the start of the next month.
+:::
+
+::: details How do I see how much AI we have used?
+Open the [AI usage](/ai/ai-usage) dashboard. It shows your usage as a percentage of your allowance, along with trends and a breakdown by member, feature, project, model, and agent.
:::
::: details Where can I see the latest included credit amounts?
diff --git a/docs/core-concepts/issues/labels.md b/docs/core-concepts/issues/labels.md
index c816431b..bde28717 100644
--- a/docs/core-concepts/issues/labels.md
+++ b/docs/core-concepts/issues/labels.md
@@ -5,39 +5,124 @@ description: Use labels to categorize work items, simplify filtering, and organi
# Work Item Labels
-Labels are keywords or tags that you can assign to work items in order to categorize and differentiate them within your project. They are ideal for tracking components or other unique identifiers that don’t fall under the standard work item properties.
+Labels are colored tags you assign to work items to categorize and differentiate them within a project. They are ideal for tracking components, features, or other classifications that don't fit the standard work item properties like state, priority, or assignee.
-Labels can be used to group work items by common attributes, such as type, feature, or any other custom classification. They make it easier to filter and find related work items across your project.
+Once labels exist, you can apply several to a single work item, then filter, group, and sort your work items by them across every layout.
+
+A label belongs to one project, so each project keeps its own set.
## Manage labels
+Labels are managed in a project's settings, and the two actions have different permission levels:
+
+- **Managing the label set** (create, edit, delete, reorder, and group labels) requires **Project Admin** access. Contributors, commenters, and guests can see labels but cannot change the set.
+- **Applying an existing label** to a work item is part of editing that work item, so anyone who can edit a work item can add or remove its labels, even if they cannot manage the label set.
+

You can manage your labels in the **Labels** tab in your project settings. From here, you can create, edit, and delete labels.
-### Create labels
+Open **Project settings → Labels** to create, edit, group, reorder, and delete your project's labels. If the project has none yet, you'll see a prompt to create your first one.
+
+### Create a label
+
+1. Click **Add label**.
+2. Enter a name and pick a color. Plane pre-selects a random color from a preset palette; you can choose a different one.
+3. Click **Add**.
+
+A few rules to know:
+
+- The **name is required** and can be up to **255 characters**.
+- Names must be **unique within the project** (case-insensitive). If you reuse a name, Plane tells you the label already exists.
+- In the app, a label has a **name and a color** only. The color picker offers a fixed palette of preset colors.
+
+You can also create a label on the fly while working, without opening settings. From a work item's label picker, type a new name and create it inline. Newly created labels there are given a color from the palette automatically.
-To create a new label:
+
-1. Click the **Add label** button.
-2. Name your label, choose a color (optional)
-3. Click **Add** to save your label.
+When you create a work item, Plane can also [**suggest labels**](/ai/plane-ai#label-prediction) based on its title and description, so you can apply relevant labels (or create suggested ones) in a click.
-You can also create labels directly from the work item detail page, making it super easy to tag work items as you go.
+### Edit a label
-
+1. Open the label's menu and choose **Edit label**.
+2. Update the name or color.
+3. Click **Update**.
-### Edit labels
+Editing is inline, the same form used to create a label, so you can change the name and color but nothing else.
-1. Click the … icon on the label you want to edit and select **Edit label**.
-2. Update the label name or color as needed.
-3. Click **Update** to save your changes.
+### Group labels
-### Delete labels
+You can nest related labels under a parent to keep a long list organized, for example grouping "Frontend," "Backend," and "Infra" under a parent called "Area."
-1. Ensure no active work items are using the label.
-2. Click the **x** icon on the label to delete it.
+- To create a group, **drag one label onto another** in the Labels list. The dragged label becomes a child of the one you drop it on, and the parent becomes a collapsible group.
+- Grouping is done entirely by drag-and-drop. There is no separate "create group" button and no parent field in the create form.
+- **Nesting is one level deep.** A label can be a parent or a child, but you cannot nest groups inside other groups.
+- A group shows as a collapsible section with its child labels indented underneath.
-::: warning
-Removing a label from your project will dissociate it from any work items that had it assigned.
+### Reorder labels
+
+Drag labels up or down in the list to set their order. The order you set is the order labels appear in pickers and filters. Reordering, like grouping, requires Project Admin access.
+
+### Delete a label
+
+1. Open the label's menu and choose to delete it.
+2. Confirm in the dialog.
+
+When you delete a label, Plane removes it from every work item that had it and from any views that were filtering on it. The work items themselves are not affected beyond losing that one label.
+
+:::warning Deleting a group deletes its children
+Deleting a parent label also deletes all of the labels nested under it, and removes those labels from their work items too. If you want to keep the child labels, drag them out of the group first.
:::
+
+## Apply labels to work items
+
+Labels are applied from wherever you edit a work item, and a work item can carry **as many labels as you need**.
+
+- **From a work item:** open it and use the label field to add or remove labels. You can create a new label inline from the same picker.
+- **From the create dialog:** set labels while creating the work item, or accept Plane's label suggestions.
+- **In bulk:** select multiple work items in the List layout, and apply labels to all of them at once.
+
+## Where labels help you across the project
+
+Once your work items are labeled, labels power several parts of the product:
+
+- **Filtering.** Filter any work item list by one or more labels, in every layout.
+- **Grouping.** Group work items by label in the board, list, and spreadsheet layouts. On the board you can drag a work item from one label group to another to relabel it.
+- **Sorting.** Order a list by label name.
+- **Display.** Show labels directly on cards and as a spreadsheet column.
+- **Queries (PQL).** Filter with the `label` field (for example `label IN (Bug, Regression)`) and the `hasNoLabel()` function to find unlabeled work. See [Plane Query Language](/core-concepts/issues/plane-query-language).
+- **Automations.** Use labels as a condition (only act on work items with certain labels) and as an action (add, remove, or replace labels when a rule fires). See [Automations](/automations/custom-automations).
+- **Views and workspace views.** Labels are available as a filter in saved project views and in workspace-level views that span projects.
+- **Templates.** Project templates can carry a predefined set of labels so new projects start with your standard taxonomy.
+
+## Import labels from a CSV
+
+Instead of adding labels one at a time, you can bulk-create them from a CSV file. This is useful when setting up a new project or migrating a label taxonomy from another tool.
+
+1. In **Project settings → Labels**, click **Import**.
+2. Upload a CSV file. Use **Download sample CSV** to get the correct format.
+3. Plane validates and processes the file, then shows a summary.
+
+### CSV format
+
+The file has three columns:
+
+| Column | Required | Notes |
+| ------------- | -------- | ----------------------------------------------------------------------------------- |
+| `name` | Yes | The label name. Blank names are reported as errors. |
+| `description` | No | Stored on the label. |
+| `color` | No | A hex color such as `#0693E3`. Invalid or blank colors get a random color assigned. |
+
+### What the import does
+
+- **Creates new labels only.** It never updates or links to existing labels.
+- **Skips duplicates.** A row whose name already exists in the project (case-insensitive), or repeats a name from earlier in the same file, is skipped rather than merged or renamed.
+- **Does not create groups.** Imported labels are flat; parent/child grouping is not carried by the CSV. You can group them afterward by drag-and-drop.
+- **Runs in the background** and reports a summary of how many labels were **Created**, **Skipped**, and **Failed**. If any rows failed, you can download an error report showing which rows and why.
+
+## Things to know
+
+- **A label belongs to one project.** To use the same taxonomy in another project, recreate the labels there, import them from a CSV, or start the project from a template that includes them.
+- **The app shows name and color only.** A `description` field exists and can be set through the CSV import and the API, but it is not shown or editable in the app today.
+- **No limits** are enforced on how many labels a project can have or how many labels a single work item can carry.
+- **Reusing a deleted label's name is allowed.** Once a label is deleted, its name is free to use again.
diff --git a/docs/core-concepts/issues/plane-query-language.md b/docs/core-concepts/issues/plane-query-language.md
index b827d69d..ba1bbcac 100644
--- a/docs/core-concepts/issues/plane-query-language.md
+++ b/docs/core-concepts/issues/plane-query-language.md
@@ -151,6 +151,7 @@ Use `text` when you want to match a term whether it appears in the title or the
| `label` | Labels applied |
| `cycle` | Cycle membership |
| `module` | Module membership |
+| `release` | Release the work item is linked to |
| `milestone` | Milestone |
| `mention` | Members mentioned in the work item |
| `createdBy` | Who created the work item |
@@ -312,6 +313,19 @@ The value can take several forms:
| `IS NULL` | Not in any module |
| `IS NOT NULL` | In a module |
+### release
+
+| Operator | Description |
+| ------------- | ------------------------------------------- |
+| `IN` | Linked to any of the specified releases |
+| `NOT IN` | Not linked to any of the specified releases |
+| `=` | Linked to this release |
+| `!=` | Not linked to this release |
+| `IS NULL` | Not linked to any release |
+| `IS NOT NULL` | Linked to a release |
+
+The `release` field is available where the releases feature is enabled. Use it with the [`earliestUnreleasedRelease()`](#release-functions) value function, for example `release = earliestUnreleasedRelease()`.
+
### milestone
| Operator | Description |
@@ -458,16 +472,27 @@ createdAt >= daysAgo(7)
### User functions
-| Function | Returns |
-| ----------------- | ----------------------------- |
-| `currentUser()` | The person running the query |
-| `inactiveUsers()` | Deactivated workspace members |
+Return a user or a list of users. Use `currentUser()` on the right of `=`; use the list-returning ones with `IN`, or pass them into a user function such as `votedBy(...)`.
+
+| Function | Returns |
+| ----------------------------------------- | ---------------------------------------------------- |
+| `currentUser()` | The person running the query |
+| `inactiveUsers()` | Deactivated workspace members |
+| `workspaceMembers()` | All active members of the workspace |
+| `membersOf("project:")` | Active members of the given project |
+| `membersOf("teamspace:")` | Active members of the given teamspace |
+| `userPropertyEquals("property", "value")` | Members whose profile matches a property (see below) |
+
+`userPropertyEquals` accepts one of these properties: `role`, `email`, `emailDomain`, `displayName`, `timezone`, `isActive`, `isBot`. If a people function resolves to nobody, the surrounding condition matches zero work items rather than being ignored.
Examples:
```
assignee = currentUser()
assignee IN (inactiveUsers())
+assignee IN membersOf("project:1a2b3c4d-...")
+assignee IN userPropertyEquals("role", "admin")
+votedBy(workspaceMembers())
```
### Cycle functions
@@ -502,26 +527,67 @@ Example:
stateGroup IN (openStates())
```
+### Release functions
+
+Return a release. Use them on the right side of a `release` condition. Available where the releases feature is enabled.
+
+| Function | Returns |
+| ----------------------------- | ---------------------------------------------------------------------------- |
+| `earliestUnreleasedRelease()` | The next unreleased release by target date (the earliest one still upcoming) |
+
+Example:
+
+```
+release = earliestUnreleasedRelease()
+```
+
## Condition functions
Standalone checks that return true or false. Combine them with `AND`, `OR`, and `NOT`. Arguments shown as `"user"`, `"date"`, `"text"`, or `n` are values you supply; you pick users and dates from the editor's suggestions.
+Functions that take a user (such as `votedBy`, `commentedBy`, `attachedBy`, or `lastCommentBy`) accept a single member, or a list-returning [people function](#people-functions) to match a whole group at once. Use `currentUser()` for the person running the query, `workspaceMembers()` for everyone, or `membersOf("project:")` for a project, for example `votedBy(currentUser())` or `votedBy(workspaceMembers())`.
+
### Structure and relationships
Relation functions each take one or more work item identifiers, for example `blockedBy("WEB-11", "WEB-20")`.
-| Function | Matches work items that | Example |
-| ---------------------- | ----------------------------------------------- | ----------------------- |
-| `isTopLevel()` | Are not a sub-work item (no parent) | `isTopLevel()` |
-| `isSubWorkItem()` | Are a sub-work item (have a parent) | `isSubWorkItem()` |
-| `hasChildren()` | Have at least one sub-work item | `hasChildren()` |
-| `hasRelations()` | Have at least one relation to another work item | `hasRelations()` |
-| `blockedBy("id", …)` | Are blocked by the given items | `blockedBy("WEB-11")` |
-| `blocks("id", …)` | Block the given items | `blocks("WEB-11")` |
-| `linkedTo("id", …)` | Are related to the given items | `linkedTo("WEB-11")` |
-| `duplicateOf("id", …)` | Are marked duplicate of the given items | `duplicateOf("WEB-11")` |
-| `childOf("id", …)` | Are a child of the given items | `childOf("WEB-11")` |
-| `parentOf("id", …)` | Are a parent of the given items | `parentOf("WEB-11")` |
+| Function | Matches work items that | Example |
+| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- |
+| `isTopLevel()` | Are not a sub-work item (no parent) | `isTopLevel()` |
+| `isSubWorkItem()` | Are a sub-work item (have a parent) | `isSubWorkItem()` |
+| `hasChildren()` | Have at least one sub-work item | `hasChildren()` |
+| `hasRelations()` | Have at least one relation to another work item | `hasRelations()` |
+| `blockedBy("id", …)` | Are blocked by the given items | `blockedBy("WEB-11")` |
+| `blocks("id", …)` | Block the given items | `blocks("WEB-11")` |
+| `linkedTo("id", …)` | Are related to the given items | `linkedTo("WEB-11")` |
+| `duplicateOf("id", …)` | Are marked duplicate of the given items | `duplicateOf("WEB-11")` |
+| `childOf("id", …)` | Are a child of the given items | `childOf("WEB-11")` |
+| `parentOf("id", …)` | Are a parent of the given items | `parentOf("WEB-11")` |
+| `linkedToAny("id", …)` | Are connected to any of the given items through one relation hop (any relation type, both directions; hierarchy not walked) | `linkedToAny("WEB-11")` |
+| `linkedToAll("id", …)` | Same as `linkedToAny`, and also walks parent/child (sub-work-item and epic) links | `linkedToAll("WEB-11", "WEB-20")` |
+| `linkedToAnyRecursive("id", …[, depth])` | Multi-hop `linkedToAny`; optional trailing depth (default 5, maximum 10) | `linkedToAnyRecursive("WEB-11", 3)` |
+| `linkedToAllRecursive("id", …[, depth])` | Multi-hop `linkedToAll`, with the same depth rules | `linkedToAllRecursive("WEB-11")` |
+| `workItemPicker("name"[, "id", …])` | Whose issue-picker [custom property](#custom-properties) (matched by display name) has any value, or points at one of the given items | `workItemPicker("Related", "WEB-11")` |
+
+Recursive traversals stop at the depth you set (5 by default, 10 at most) and are capped at a maximum number of work items. `workItemPicker("Related")` with no ids matches any work item whose "Related" picker has a value.
+
+### Rollups
+
+`aggregate("scope", "field", "agg", "threshold")` matches a work item when a numeric rollup meets a comparison. It takes exactly four arguments:
+
+| Argument | Allowed values |
+| ----------- | ------------------------------------------------------------------------------------ |
+| `scope` | `children` (roll up the work item's sub-work items) or `self` (the work item itself) |
+| `field` | `estimate` (points-type estimates only) or `worklog` (logged time, in **minutes**) |
+| `agg` | `sum`, `avg`, `min`, `max`, or `count` |
+| `threshold` | A comparison such as `"> 10"` or `">= 2.5"`. A bare number is treated as `>= n`. |
+
+```
+aggregate("children", "estimate", "sum", "> 10")
+aggregate("self", "worklog", "sum", ">= 480")
+```
+
+Only points-type estimates are counted; time and category estimates are ignored. For `sum` and `count`, a work item with no matching rows counts as 0.
### Assignees and labels
@@ -541,17 +607,22 @@ Relation functions each take one or more work item identifiers, for example `blo
Count arguments accept a number or a comparison such as `">= 2"`.
-| Function | Matches work items that | Example |
-| ------------------------- | ------------------------------------------------ | ------------------------------- |
-| `hasComments([n])` | Have comments, optionally a count | `hasComments(">= 3")` |
-| `commentedAfter("date")` | Have a comment on or after the date | `commentedAfter("2026-01-01")` |
-| `commentedBefore("date")` | Have a comment on or before the date | `commentedBefore("2026-06-30")` |
-| `commentContains("text")` | Have a comment containing the text | `commentContains("blocker")` |
-| `lastCommentBy("user")` | Whose most recent comment is by the user | `lastCommentBy("Priya")` |
-| `hasLinks([n])` | Have URL links, optionally a count | `hasLinks(">= 1")` |
-| `linkContains("text")` | Have a link whose URL or title contains the text | `linkContains("figma")` |
-| `hasAttachments([n])` | Have attachments, optionally a count | `hasAttachments(">= 2")` |
-| `attachedBy("user")` | Have an attachment uploaded by the user | `attachedBy("Priya")` |
+| Function | Matches work items that | Example |
+| ------------------------- | ------------------------------------------------ | ------------------------------------------ |
+| `hasComments([n])` | Have comments, optionally a count | `hasComments(">= 3")` |
+| `commentedAfter("date")` | Have a comment on or after the date | `commentedAfter("2026-01-01")` |
+| `commentedBefore("date")` | Have a comment on or before the date | `commentedBefore("2026-06-30")` |
+| `commentContains("text")` | Have a comment containing the text | `commentContains("blocker")` |
+| `lastCommentBy("user")` | Whose most recent comment is by the user | `lastCommentBy("Priya")` |
+| `commentedBy("user")` | Have a comment written by the user | `commentedBy("Priya")` |
+| `hasLinks([n])` | Have URL links, optionally a count | `hasLinks(">= 1")` |
+| `hasRemoteLinks()` | Have at least one link to an external URL | `hasRemoteLinks()` |
+| `linkContains("text")` | Have a link whose URL or title contains the text | `linkContains("figma")` |
+| `hasLinkUrl("url")` | Have a link at exactly this URL (exact match) | `hasLinkUrl("https://figma.com/file/abc")` |
+| `hasAttachments([n])` | Have attachments, optionally a count | `hasAttachments(">= 2")` |
+| `attachedBy("user")` | Have an attachment uploaded by the user | `attachedBy("Priya")` |
+
+Use `linkContains` for a partial match on a link's URL or title, and `hasLinkUrl` when you want to match one exact URL.
### Worklogs and activity
@@ -561,3 +632,30 @@ Count arguments accept a number or a comparison such as `">= 2"`.
| `workLoggedBy("user")` | Have time logged by the user | `workLoggedBy("Priya")` |
| `workLoggedBetween("from", "to")` | Have time logged between two dates | `workLoggedBetween("2026-01-01", "2026-01-31")` |
| `recentlyViewed()` | You viewed in the last 30 days | `recentlyViewed()` |
+
+### Votes and history
+
+These match work items based on who took an action on them. Each takes exactly one user (pick a member, or use `currentUser()`).
+
+| Function | Matches work items that | Example |
+| ------------------------ | --------------------------------------------- | ------------------------- |
+| `votedBy("user")` | Were upvoted by the user | `votedBy("Priya")` |
+| `stateChangedBy("user")` | Had their state changed by the user | `stateChangedBy("Priya")` |
+| `resolvedBy("user")` | Were moved into a completed state by the user | `resolvedBy("Priya")` |
+
+### Modules and releases
+
+| Function | Matches work items that | Example |
+| ----------------------- | ------------------------------------------------------------------ | ------------------------- |
+| `inNextRelease()` | Are linked to the next upcoming unreleased release | `inNextRelease()` |
+| `releaseMatch("regex")` | Are linked to an unreleased release whose name matches the pattern | `releaseMatch("v2\\..*")` |
+| `moduleMatch("regex")` | Are in a module whose name matches the pattern | `moduleMatch("^Front")` |
+
+`releaseMatch` and `moduleMatch` match names with a regular expression. The pattern is **case-sensitive** and **unanchored** (it matches anywhere in the name unless you anchor it with `^` or `$`). Start the pattern with `(?i)` to match case-insensitively, for example `moduleMatch("(?i)frontend")`. Patterns are limited to 200 characters.
+
+Besides standing on their own, `moduleMatch` and `releaseMatch` can also be used as value functions on the right side of `IN`, so you can match by name inside a list:
+
+```
+module IN moduleMatch("Front")
+release IN releaseMatch("v2")
+```
diff --git a/docs/core-concepts/pages/editor-blocks.md b/docs/core-concepts/pages/editor-blocks.md
index cda8010d..fba835f2 100644
--- a/docs/core-concepts/pages/editor-blocks.md
+++ b/docs/core-concepts/pages/editor-blocks.md
@@ -1,6 +1,7 @@
---
title: Editor blocks for pages
description: Explore all available content blocks in Plane's Page editor.
+outline: 2
---
# Editor blocks
@@ -228,6 +229,65 @@ HTML artifacts run in a sandboxed frame that is isolated from Plane. The embedde
Creates visually distinct sections with customizable icons and colors for highlighting warnings, tips , and calls-to-action.
+## Toggle
+
+A toggle is a collapsible block that hides its content behind a title. Readers see the title, and click to expand it when they want the detail. Toggles keep long documents tidy: use them for optional context, FAQs, step-by-step details, or anything you want available without cluttering the page.
+
+Toggles are available anywhere you use the editor, including **pages**, **wiki pages**, and **work item descriptions**.
+
+### Insert a toggle
+
+1. Place your cursor where you want the toggle.
+2. Type `/` to open the command menu.
+3. Search for **Toggle**. You can also type `/accordion`, `/expand`, `/collapse`, `/details`, or `/summary` to find it.
+4. Select it. Plane inserts an open toggle with the cursor in its title, ready for you to type.
+
+### Add a title and content
+
+A toggle has two parts:
+
+- **The title** is the line that always stays visible. Type the title first. An empty title shows the hint "Give this a title..."
+- **The body** is the content that expands and collapses. Press **Enter** from the title to move into the body, then add your content. An empty body shows "Empty toggle. Click or drop a block inside."
+
+The body can hold almost anything the editor supports: paragraphs, lists, headings, images, callouts, and more. You can also **nest toggles inside toggles** to build layered, collapsible sections.
+
+### Expand and collapse
+
+Click the arrow next to the title to expand or collapse a toggle. A newly inserted toggle starts **expanded** so you can add content right away.
+
+Toggles keep working in read-only and published views: anyone viewing the page can click to expand and collapse them, even when they cannot edit.
+
+### Things to know
+
+- **The open or closed state is not saved.** Collapsing or expanding a toggle changes what you see, but it is not written into the document. If you reload the page, toggles return to their default state rather than staying exactly as you left them. This also means every reader sees toggles in their default state, not whatever a previous viewer left behind.
+- **Removing a toggle.** Pressing **Backspace** at the start of an empty title removes the toggle and keeps you in the document.
+
+## Table of contents
+
+On a long page, a table of contents gives readers a quick map of the content and a way to jump straight to any section. Plane builds it from the **headings** in your page, so there is nothing to maintain by hand: as you add, rename, reorder, or remove headings, the table of contents updates on its own.
+
+The table of contents is available on **pages** and **wiki pages**. It is not available in work item descriptions or comments, which don't track headings.
+
+A table of contents only shows what it can find, so start by giving your page headings. Type `/` and choose a heading (Heading 1, Heading 2, or Heading 3), or use Markdown shortcuts by starting a line with `#`, `##`, or `###`. Until a page has at least one heading, the table of contents shows an empty message.
+
+### Insert a table of contents
+
+1. Place your cursor where you want the table of contents, usually near the top of the page.
+2. Type `/` to open the command menu.
+3. Search for **Table of contents**. You can also type `/toc`, `/contents`, `/outline`, or `/headings` to find it.
+4. Select it. Plane inserts the block, described as "a live outline of this page's headings," and adds an empty line after it so you can keep writing.
+
+The block lists every heading on the page, indented by level so the structure is easy to scan.
+
+### How it behaves
+
+- **Shows every heading level.** Headings from level 1 through level 6 all appear, each indented according to its level.
+- **Stays up to date.** The list rebuilds automatically whenever you add, edit, reorder, or delete a heading. You never edit the table of contents directly.
+- **Jumps to a section.** Click any entry to smoothly scroll the page to that heading.
+- **Handles empty headings.** A heading with no text yet appears as "Untitled heading" until you name it.
+
+Because it is a normal block, you can drag it to move it elsewhere on the page, or delete it like any other block.
+
## AI block
Generate or transform content directly within your pages using AI. The AI Block lets you draft new content, summarize existing text, or run custom prompts without leaving the editor.
diff --git a/docs/dashboards.md b/docs/dashboards.md
index 1382c8d8..c4d25987 100644
--- a/docs/dashboards.md
+++ b/docs/dashboards.md
@@ -341,6 +341,72 @@ Pick the project, then the cycle within that project to summarize. The widget th
The widget reports on one cycle. To track several cycles, add one widget per cycle.
+### Intake accepted vs declined
+
+The intake accepted vs declined widget plots two time series side by side: how many intake requests were accepted and how many were declined over a period you choose. It is most useful for seeing how your triage decisions trend and whether the balance between accepting and declining is shifting.
+
+**Basic**
+
+Configure the widget with:
+
+- **Date grouping** - bucket the timeline by Day, Week, Month (default), or Year. Each bucket counts the decisions made in that period, by the date the decision was made.
+- **Chart style** - show the two series as a **Multi-line** chart (default) or a **Stacked bar** chart.
+
+Style options:
+
+- **Legends** and **Tooltip** - toggle each on or off.
+
+Accepted counts intake items you accepted; declined counts items you rejected or marked as a duplicate. Pending and snoozed items are not counted. The axes and group-by are fixed, the Accepted series is always green and Declined always red, and there are no widget-level filters. Point the dashboard at projects that use Intake; projects with no intake items contribute nothing.
+
+### Average time to accept and decline
+
+This widget tracks how long intake requests take to reach a decision - the average time between when an item arrived in intake and when it was accepted or declined - so you can see whether triage is getting faster or slower.
+
+**Basic**
+
+Configure the widget with:
+
+- **Date grouping** - Day, Week, Month (default), or Year. Each bucket shows the average decision time for the items decided in that period.
+- **Display** - **Line** (default), a trend of average time per period; or **Number**, a single figure showing the overall average across the whole range.
+
+Style options:
+
+- **Legends** and **Tooltip** apply to the line display.
+- **Text alignment** and **text color** apply to the number display.
+
+The average is measured in days from an item's creation in intake to its decision, across all decided items (accepted, rejected, and duplicate). Pending and snoozed items are excluded. In the line display, a period with no decisions leaves a gap rather than dropping to zero.
+
+### Intake breakdown
+
+The intake breakdown widget is a compact snapshot of intake activity across the dashboard's projects. Instead of a chart, it shows a fixed set of headline numbers so you can read the state of your intake at a glance.
+
+**Basic**
+
+The widget always displays the same six metrics:
+
+- **In-app volume**, **Email volume**, **Form volume** - counts of intake items by source, across all statuses.
+- **Total accepted** and **Total rejected** - decided counts.
+- **Avg. time to decide** - average number of days from an item's arrival to its decision.
+
+The only setting is **View**: **Grid** (default), showing the metrics as tiles, or **Table**, showing them as a two-column list. This is a presentation choice only; it does not change the numbers, and the widget is not narrowed by widget-level filters.
+
+### Intake items ageing
+
+The intake items ageing widget shows how long your undecided intake requests have been waiting, grouping items that still need a decision into age bands so you can spot a backlog before it goes stale.
+
+**Basic**
+
+Configure the widget with:
+
+- **Color scheme** - Modern, Horizon (default), or Earthen.
+- **Center value** - show the total count of undecided items in the middle of the ring (on by default).
+
+Style options:
+
+- **Legends** and **Tooltip** - toggle each on or off.
+
+The widget renders a donut split into three fixed age bands: **0-2 days**, **3-7 days**, and **7+ days**. It covers only undecided items (pending and snoozed); accepted, rejected, and duplicate items are not shown. Each item is aged from its arrival date in intake, and the age bands cannot be changed.
+
## Configure a widget
Open the configuration sidebar by clicking the widget or by clicking the pencil icon.
diff --git a/docs/pages/edit-ms-office-files.md b/docs/pages/edit-ms-office-files.md
new file mode 100644
index 00000000..101a644b
--- /dev/null
+++ b/docs/pages/edit-ms-office-files.md
@@ -0,0 +1,49 @@
+---
+title: Edit Microsoft Office Files
+description: Edit Word, Excel, and PowerPoint files attached to a wiki page directly in your desktop Microsoft Office app, with changes saved back to Plane.
+---
+
+# Edit Microsoft Office Files
+
+You can edit Microsoft Office files that are attached to a **wiki page** without downloading them, re-uploading them, and losing track of versions. Plane opens the attachment in the **Microsoft Office desktop app** already installed on your computer, and when you save in Office, the changes are written straight back to the same attachment on the page.
+
+This is real editing of the file in place, not a preview and not a separate copy. The attachment keeps its place on the page, and everyone sees the updated version.
+
+## Requirements
+
+- You need the **Microsoft Office desktop app** (Word, Excel, or PowerPoint) installed on your computer. Plane opens the file in that app; it is not an in-browser editor.
+- You need a **desktop web browser**. This does not work on mobile.
+- Your Plane site must be served over **HTTPS**. On Plane Cloud this is always the case. Self-hosted instances must be configured with HTTPS.
+
+## Supported file types
+
+Editing works with the standard Office formats:
+
+- **Word:** `.doc`, `.docx`
+- **Excel:** `.xls`, `.xlsx`
+- **PowerPoint:** `.ppt`, `.pptx`
+
+## Where it works
+
+This feature is limited to **attachments on wiki pages**. Office files attached to work items or added to comments cannot be edited this way; they can still be downloaded and re-uploaded as usual.
+
+## Edit a file
+
+1. Attach an Office file to a wiki page, or open a page that already has one.
+2. On the attachment, click **Edit**.
+3. Your browser asks to open the file in the matching Microsoft Office app. Allow it.
+4. The file opens in the desktop app. Make your changes and **save** in Office as you normally would.
+5. Your saves are written back to the attachment in Plane. When you are done, close the file in Office.
+
+You do not need to re-upload anything. The file on the page updates in place and keeps the same attachment.
+
+## While you are editing
+
+To prevent two people from overwriting each other, the file is **locked** while it is open for editing. During that time, another person cannot start editing the same attachment. The lock is released when you finish, and it also expires on its own after a period of inactivity, so a file is never left locked forever if an editing session is abandoned.
+
+## Notes and limits
+
+- **Desktop only.** Editing requires the desktop Office app and a desktop browser. There is no in-browser or mobile editing.
+- **Your local Office app does the editing.** Plane does not convert the file or render it in the browser. It hands the file to Word, Excel, or PowerPoint on your machine over a secure connection, and commits your saves back.
+- **The file stays the same file.** Edits keep the same attachment rather than creating a new copy, so links to it stay valid and its history stays in one place.
+- **Wiki pages only.** Work item and comment attachments are not covered.
diff --git a/docs/projects/project-audit-logs.md b/docs/projects/project-audit-logs.md
new file mode 100644
index 00000000..81b560a3
--- /dev/null
+++ b/docs/projects/project-audit-logs.md
@@ -0,0 +1,95 @@
+---
+title: Project Audit Logs
+description: Give project admins a tamper-evident record of who changed a project's configuration, membership, permissions, and settings, with filtering and export.
+---
+
+# Project Audit Logs
+
+The project audit log is a focused record of security-relevant activity **within a single project**. It gives project admins an accountable, time-stamped history of who changed the project's configuration, membership, permissions, and settings.
+
+Like [Workspace Audit Logs](/workspaces-and-users/audit-logs), project audit entries are **append-only** and **tamper-evident**: they are written once and can never be edited or deleted, by anyone, including administrators. In fact, project and workspace audit entries are the same underlying records. The project audit log is the slice scoped to one project, so a project admin can review their own project's history without needing access to the whole workspace.
+
+## Where to find it
+
+Go to **Project settings → Audit logs**. The page shows the most recent events first, with filters and an export option at the top.
+
+## What gets tracked
+
+The project audit log records actions taken on this project:
+
+| Category | Events tracked |
+| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| **Project** | Project settings updated; create, update, or delete of the project's states, labels, modules, cycles, views, workflows, and automations (including enabling or disabling an automation) |
+| **Member** | Member added to the project, member removed from the project |
+| **Role and permission** | Project member role changed |
+| **Security** | Audit log searched, exported, and export downloaded |
+
+Reading and exporting the project audit log are themselves recorded as events, so every access to the log is accountable.
+
+The project audit log deliberately covers only project-scoped activity. Workspace-wide events, such as sign-ins, plan changes, API tokens, and webhooks, are not shown here. Those belong to the [workspace audit log](/workspaces-and-users/audit-logs) and the instance-level logs.
+
+## Read the log
+
+Each row represents one event, with these columns:
+
+| Column | What it shows |
+| ---------------- | ------------------------------------------------------------------------------------------------- |
+| **Timestamp** | The date and time the event occurred, in your local time |
+| **Actor** | Who performed the action, shown by name or email. System-generated actions show as **System** |
+| **Event** | The action that took place, for example "Project member role changed" |
+| **Event object** | The target the action was performed on, for example the affected member or the label that changed |
+| **Category** | The category the event belongs to, with an icon |
+
+Behind each entry, the log also captures additional context that appears in exports, including the actor type (user, API token, system, or anonymous), the outcome (success or failure), the IP address, the user agent, and, where relevant, the old and new values that changed.
+
+Actor identity is stored as a snapshot at the time of the event. If a member is later renamed or removed, historical entries still show who they were when the action happened.
+
+## Filter and search
+
+Use the filters at the top of the page to narrow the log:
+
+- **Category** — Project, Member, Role & Permission, or Security
+- **Outcome** — successful or failed events
+- **Actor** — events performed by a specific person
+- **Date range** — events within a start and end date
+- **Search** — free-text search across events
+
+Filters combine, and the filters you apply also determine what is included when you export.
+
+## Export the log
+
+You can export the project audit log for offline review, archiving, or handing to auditors.
+
+1. Apply any filters you want the export to respect.
+2. Click the **Download** button.
+3. Choose a format: **CSV**, **JSON**, or **Excel (XLSX)**.
+
+The export runs in the background. When it is ready, download it from the **Previous exports** list, which records who exported, when, the format, and the status. Because exporting reflects your current filters, you can produce a targeted export, for example only this month's membership changes, rather than the entire log.
+
+## Data integrity
+
+The project audit log is designed so it can be trusted as evidence:
+
+- **Append-only.** Entries cannot be modified or deleted after they are written. This is enforced in the application and at the database level, so there is no path, even for an administrator, to alter history.
+- **Tamper-evident.** Each entry is cryptographically chained to the one before it. If any entry were altered or removed, the chain would no longer validate. Programmatic chain verification is available through the audit log API at the workspace level.
+
+## Notes and limits
+
+- Project audit entries are permanent. There is no way to clear or prune the log, and logs are retained indefinitely.
+- The project audit log is not an activity feed for individual work items. For the history of a specific work item, use that work item's activity view.
+- Project audit entries also appear in the [workspace audit log](/workspaces-and-users/audit-logs), which a workspace admin can use to review activity across every project at once.
+- The tracked event set expands over time as coverage grows.
+
+## Frequently asked questions
+
+**Can a project admin delete an entry to hide an action?**
+No. The log is append-only and enforced at the database level. No one, including workspace owners, can edit or delete entries.
+
+**Do login events show up in the project audit log?**
+No. Sign-in and authentication events are recorded at the instance level, not in the project or workspace audit log.
+
+**Does viewing the project audit log show up in the log?**
+Yes. Searching and exporting the log are recorded as events, so access to the log is itself accountable.
+
+**Who can see the project audit log?**
+Project Admins, plus Workspace Admins and Owners. It is hidden from members and guests.
diff --git a/docs/projects/project-releases.md b/docs/projects/project-releases.md
new file mode 100644
index 00000000..529062d1
--- /dev/null
+++ b/docs/projects/project-releases.md
@@ -0,0 +1,65 @@
+---
+title: Project Releases
+description: Group a single project's work items into named versions, track delivery progress, and publish a changelog, all within the project.
+---
+
+# Project Releases
+
+Project releases let you group work items from **one project** into a named, versioned deliverable, track its progress, and publish a changelog. They are the project-scoped version of Plane's [Releases](/releases) feature: the same release model, but each release belongs to a single project and is managed from within that project.
+
+Use project releases when a project ships on its own cadence and you want its versions kept inside the project, rather than as workspace-wide releases that span several projects.
+
+## Project releases vs workspace releases
+
+Both work the same way. The only difference is scope and where they live.
+
+| | Project releases | Workspace releases |
+| -------------------------------- | --------------------------------- | ------------------------------------- |
+| Scope | One project | The whole workspace |
+| Work items a release can contain | Only work items from that project | Work items from any project |
+| Where you manage them | The project's **Releases** tab | **Releases** in the workspace sidebar |
+| Enabled | Per project, in project settings | Per workspace, in workspace settings |
+
+If you need a single release to pull work from several projects at once, use [workspace releases](/releases) instead.
+
+## Enable releases for a project
+
+Project releases are off until an admin turns them on for the project.
+
+1. Go to **Project settings → Features**.
+2. Find **Releases** and toggle it on ("Create releases in this project, add work items to them, and ship them together").
+
+Once enabled, a **Releases** tab appears in the project, and work items in the project gain a Releases property.
+
+## Where to find them
+
+Open the project and select the **Releases** tab. Releases are listed and grouped by status (Unreleased, Released, Cancelled). From here you create a release and open any release to work on it.
+
+## Create and work with a release
+
+Creating a release, its **Unreleased / Released / Cancelled** lifecycle, the **Overview**, **Scope**, and **Changelog** tabs, the progress rollup, and the manually written changelog all behave exactly as they do for workspace releases. See [Releases](/releases) for the full walkthrough. A quick summary:
+
+- **Create** a release with a name, description, status, tag, labels, target date, and lead. Names are unique across the workspace.
+- **Overview** shows the release's properties and a live progress bar (completed, pending, and cancelled counts based on each work item's state).
+- **Scope** is the set of work items in the release.
+- **Changelog** is a separate rich-text document for your outward-facing release notes. It starts blank and is written by hand; Plane does not generate it from the work items.
+- **Status** is set manually. Marking a release **Released** does not happen automatically when all work is done, and you can record the actual release date at that point.
+
+## Add work items (the key difference)
+
+A project release can only contain work items from its **own project**. When you open the release's **Scope** tab and click **Add work items**, the search is limited to that project. Trying to add a work item from another project is rejected.
+
+This is the one behavioral difference from workspace releases, which can pull work items from any project. Everything else about adding and removing scope is the same: adding a work item creates a link without moving or changing it, and removing it only removes the link.
+
+## Link releases from a work item
+
+Work items in a release-enabled project have a **Releases** property in their detail panel, next to Cycle and Module, and as a column in the spreadsheet and board layouts. You can link a release from the work item instead of from the Scope tab, and a work item can belong to more than one release.
+
+In the release picker, releases are grouped into **Project releases** and **Workspace releases**, so you can tell which scope each one belongs to.
+
+For the full behavior of the Releases property, the separate **Release picker** custom property, and filtering work items by release including in [PQL](/core-concepts/issues/plane-query-language), see [Releases](/releases).
+
+## Availability and permissions
+
+- Project releases require the project releases entitlement on your plan, and the per-project **Releases** feature toggle must be on. This entitlement is separate from workspace releases, so a workspace can have one, the other, or both.
+- Managing releases (create, edit, delete, change scope) follows your project role. Members with the release permissions in the project can manage them; others can view.
diff --git a/docs/releases.md b/docs/releases.md
index bc5767a8..4efaeb41 100644
--- a/docs/releases.md
+++ b/docs/releases.md
@@ -1,15 +1,17 @@
---
-title: Releases
+title: Workspace Releases
description: Group work items under named versions, track delivery progress, and publish changelogs to keep your team aligned on what ships and when.
---
-# Releases
+# Workspace Releases
-A release is how you communicate what your team is shipping and when. It groups work items from across your workspace into a named, versioned deliverable - with a target date, a lead, a changelog, and a clear status that tells everyone whether this version is in progress, out the door, or cancelled.
+A release is how you communicate what your team is shipping and when. It groups work items from across your workspace into a named, versioned deliverable — with a target date, a lead, a changelog, and a clear status that tells everyone whether this version is in progress, out the door, or cancelled.

-Releases live at the workspace level, not the project level. That means a single release can pull in work items from multiple projects. A release for "v2.3.0" might include a backend fix from your API project, a UI change from your web project, and a docs update from your content project - all tracked together in one place.
+These workspace releases live at the workspace level, so a single release can pull in work items from multiple projects. A release for "v2.3.0" might include a backend fix from your API project, a UI change from your web project, and a docs update from your content project, all tracked together in one place.
+
+Plane also offers **project releases**, a version of the same feature scoped to a single project and enabled per project. If you want to group and ship one project's work on its own, see [Project releases](/projects/project-releases). Everything on this page about creating, scoping, and shipping a release applies to both; the difference is only their scope.
This is the key distinction between releases and cycles. Cycles are sprint containers - time-boxed, project-scoped, for managing ongoing development. Releases are version containers - for grouping and communicating deliverables across projects, regardless of which cycle the work was done in.
diff --git a/docs/workspaces-and-users/audit-logs.md b/docs/workspaces-and-users/audit-logs.md
index 6c5803b6..64cf373a 100644
--- a/docs/workspaces-and-users/audit-logs.md
+++ b/docs/workspaces-and-users/audit-logs.md
@@ -1,9 +1,9 @@
---
-title: Workspace Audit logs
+title: Workspace Audit Logs
description: Track key actions across your workspace with a dedicated, tamper-evident audit log. View, filter, and export a record of authentication, membership, role, settings, integration, and security events.
---
-# Workspace Audit logs
+# Workspace Audit Logs
The workspace audit log is a dedicated record of key actions taken across your workspace. It gives administrators an accountable, time-stamped history of who did what and when, covering sign-ins, membership changes, role changes, settings changes, integration activity, and security-sensitive events.