Skip to content

[research] Describe tags#3735

Merged
junaway merged 3 commits intomainfrom
research/tags
Feb 20, 2026
Merged

[research] Describe tags#3735
junaway merged 3 commits intomainfrom
research/tags

Conversation

@junaway
Copy link
Contributor

@junaway junaway commented Feb 11, 2026

Copilot AI review requested due to automatic review settings February 11, 2026 12:26
@vercel
Copy link

vercel bot commented Feb 11, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agenta-documentation Ready Ready Preview, Comment Feb 20, 2026 10:49am

Request Review

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces comprehensive design documentation for a Tags system on a legacy branch. The documentation provides a foundation for implementing user-facing tags that enable better organization and discovery of entities across the system. The design is intentionally lightweight and provisional given the legacy nature of the target branch.

Changes:

  • Added PRD defining product goals, use cases, scope, and success metrics for a Tags feature
  • Added RFC proposing technical architecture including data model, API design, and implementation considerations
  • Added README documenting the purpose and structure of the design artifacts

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
docs/designs/tags/README.md Introduces the design documentation folder with overview of included documents and usage guidelines
docs/designs/tags/PRD.md Defines product requirements including problem statement, goals, scope, UX/functional requirements, and future vision for Saved Views
docs/designs/tags/RFC.md Proposes technical implementation with data model, API design, backend/frontend behavior, and migration considerations
docs/designs/tags/PR.md Provides a PR template/draft with summary, rationale, scope boundaries, and reviewer checklist

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@dosubot dosubot bot added the lgtm This PR has been approved by a maintainer label Feb 16, 2026
@junaway junaway closed this Feb 20, 2026
@junaway junaway reopened this Feb 20, 2026
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings February 20, 2026 10:45
@junaway junaway marked this pull request as ready for review February 20, 2026 10:47
@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Feb 20, 2026
@junaway junaway merged commit 2b1750a into main Feb 20, 2026
6 of 7 checks passed
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +43 to +66
### Tag CRUD

- `GET /v1/tags?workspace_id=...`
- `POST /v1/tags`
- `PATCH /v1/tags/{tag_id}`
- `DELETE /v1/tags/{tag_id}`

### Tag Assignment

- `POST /v1/{entity_type}/{entity_id}/tags` (assign)
- `DELETE /v1/{entity_type}/{entity_id}/tags/{tag_id}` (unassign)
- `GET /v1/{entity_type}/{entity_id}/tags`

### Entity List Filtering

- Add query params:
- `tag_ids=...` or `tags=...`
- optional `tag_match=and|or` (default TBD)

## 5. Backend Behavior

- Normalize names on create/rename.
- Reject duplicate names in same workspace.
- Enforce workspace isolation on all joins.
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The API section scopes GET /v1/tags via workspace_id query param, but the other tag CRUD and assignment endpoints don’t specify how workspace is determined (auth context vs request body vs derived from entity). Please clarify the workspace scoping for POST/PATCH/DELETE and for {entity_type}/{entity_id}/tags so consumers know what to send and how isolation is enforced.

Suggested change
### Tag CRUD
- `GET /v1/tags?workspace_id=...`
- `POST /v1/tags`
- `PATCH /v1/tags/{tag_id}`
- `DELETE /v1/tags/{tag_id}`
### Tag Assignment
- `POST /v1/{entity_type}/{entity_id}/tags` (assign)
- `DELETE /v1/{entity_type}/{entity_id}/tags/{tag_id}` (unassign)
- `GET /v1/{entity_type}/{entity_id}/tags`
### Entity List Filtering
- Add query params:
- `tag_ids=...` or `tags=...`
- optional `tag_match=and|or` (default TBD)
## 5. Backend Behavior
- Normalize names on create/rename.
- Reject duplicate names in same workspace.
- Enforce workspace isolation on all joins.
### Workspace scoping
- All tag data is tenant-scoped by `workspace_id`.
- Clients MUST NOT be able to read, create, update, or assign tags across workspaces.
- The server derives `workspace_id` from:
- The explicit `workspace_id` query parameter (for `GET /v1/tags`), and
- The authenticated workspace context and/or target entity (for all other endpoints).
### Tag CRUD
- `GET /v1/tags?workspace_id=...`
- `workspace_id` query param is REQUIRED and determines which workspace’s tags are listed.
- The caller MUST be authorized for the requested `workspace_id`.
- `POST /v1/tags`
- `workspace_id` is derived from the authenticated workspace context; the request body MUST NOT override it.
- The new tag is always created in the caller’s current workspace.
- `PATCH /v1/tags/{tag_id}`
- `tag_id` is looked up in the caller’s workspace only.
- Requests that attempt to operate on a tag outside the caller’s workspace MUST be rejected.
- `DELETE /v1/tags/{tag_id}`
- `tag_id` is resolved within the caller’s workspace only.
- Cross-workspace deletes MUST NOT be allowed.
### Tag Assignment
- `POST /v1/{entity_type}/{entity_id}/tags` (assign)
- The `{entity_type}/{entity_id}` is first resolved to a concrete entity and its `workspace_id`.
- All `tag_id`s in the request MUST belong to the same `workspace_id` as the entity.
- Assignments that would cross workspace boundaries MUST be rejected.
- `DELETE /v1/{entity_type}/{entity_id}/tags/{tag_id}` (unassign)
- The entity and `tag_id` are both resolved and validated to belong to the same `workspace_id`.
- `GET /v1/{entity_type}/{entity_id}/tags`
- Returns only tags from the entity’s `workspace_id`.
### Entity List Filtering
- Add query params:
- `tag_ids=...` or `tags=...`
- optional `tag_match=and|or` (default TBD)
- filters are always evaluated within the current `workspace_id` context
## 5. Backend Behavior
- Normalize names on create/rename.
- Reject duplicate names in same workspace.
- Enforce workspace isolation on all joins and API operations:
- All lookups for `tags` and `entity_tags` MUST include `workspace_id` in the predicate.
- `GET /v1/tags` MUST require `workspace_id` and restrict results to that workspace.
- `POST/PATCH/DELETE /v1/tags` MUST derive `workspace_id` from the authenticated context and MUST NOT allow the client to change it.
- `{entity_type}/{entity_id}/tags` endpoints MUST derive `workspace_id` from the target entity and validate that all referenced tags share the same `workspace_id`.

Copilot uses AI. Check for mistakes.
Comment on lines +59 to +60
- `tag_ids=...` or `tags=...`
- optional `tag_match=and|or` (default TBD)
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The filtering proposal lists both tag_ids and tags as possible query params and leaves tag_match default as TBD. To avoid ambiguous client/server behavior, pick a single canonical parameter name and specify the expected encoding (e.g., comma-separated vs repeated params) plus the default match semantics.

Suggested change
- `tag_ids=...` or `tags=...`
- optional `tag_match=and|or` (default TBD)
- `tag_ids` (repeated): e.g. `?tag_ids=<tag_id_1>&tag_ids=<tag_id_2>`
- optional `tag_match=and|or` (default `and`; `and` = entity must have all listed `tag_ids`, `or` = entity must have at least one)

Copilot uses AI. Check for mistakes.

## 8. Security and Auditing

- Authorization follows existing entity-level permissions.
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security section says authorization follows existing entity-level permissions, but tag CRUD operations are not inherently entity-scoped. Please document what permission model applies to tag CRUD (e.g., workspace-level roles) and how it interacts with workspace-scoped uniqueness/isolation.

Suggested change
- Authorization follows existing entity-level permissions.
- Tag CRUD (`/v1/tags*`) is authorized via workspace-level permissions (e.g., caller must have permission to manage tags within the target `workspace_id`).
- Tag assignment/unassignment endpoints require both: (a) authorization to modify the target entity under existing entity-level permissions, and (b) authorization in the entity’s workspace to modify its tags.
- All tag operations are constrained to the caller’s authorized workspace; `workspace_id` is required/derived from context, and tag uniqueness and lookups are always enforced per workspace to prevent cross-workspace access.

Copilot uses AI. Check for mistakes.
@dosubot dosubot bot added the documentation Improvements or additions to documentation label Feb 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation lgtm This PR has been approved by a maintainer size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants