Skip to content

fix(tasks): make bulk status changes atomic - #1873

Merged
tinsever merged 3 commits into
mainfrom
fix/review-09-bulk-status
Sep 30, 2026
Merged

tinsever merged 3 commits into
mainfrom
fix/review-09-bulk-status

Conversation

@tinsever

@tinsever tinsever commented Sep 29, 2026 •

Copy link
Copy Markdown
Member

what changed?

a bulk status request could update one project before discovering that another project rejected the status. validate all destinations first, commit the writes together, and publish events after commit.

finding 09 from the codebase review.

how did you check it?

postgres multi-project status regression proving failed requests leave all tasks unchanged.

checked the combined fix tree with the full workspace test run, uncached workspace typechecks, lint, i18n and openapi checks. postgres integration tests used disposable local test databases; provider and s3 calls were mocked.

Native GitHub stack #1886 (bottom to top): #1873 (this PR) → #1876 → #1877 → #1878 → #1879. Stack base: fix/review-06-integration-scope, the shared #1867 foundation. Merge #1867 first, then move this stack's base to main before merging board changes. If GitHub has not moved it automatically, unstack the still-open board PRs, retarget #1873 to main, and recreate this native stack in the same order.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-30T11:12:28.920376Z 3d62ef3 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Mixed activity

Activity patterns show a mix of organic and automated signals.

View full analysis →

This is an automated analysis by AgentScan

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Make bulk task status changes atomic across projects

🐞 Bug fix 🧪 Tests 🕐 20-40 Minutes

Grey Divider

AI Description

• Validate every project’s destination before changing any task status.
• Commit status changes together, then publish events using the committed task values.
• Add a PostgreSQL regression test confirming invalid destinations leave all tasks unchanged and
 emit no events.
Diagram

graph TD
  R["Bulk status request"] --> V["Project validation"] --> D["Column destinations"] --> T["Status transaction"] --> DB[("Task database")] --> E["Post-commit events"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Validate inside the transaction
  • ➕ Could reduce the gap between destination validation and status updates if columns change concurrently.
  • ➖ Would keep a transaction open during per-project validation and require validation queries to use its connection.

Recommendation: The proposed prevalidation followed by one transaction directly fixes partial updates without holding a transaction open for every validation query. Consider transaction-scoped validation separately only if concurrent column changes must be guarded against.

Files changed (2) +93 / -33

Bug fix (1) +51 / -33
bulk-update-tasks.tsCommit multi-project status changes together +51/-33

Commit multi-project status changes together

• Validates and resolves destination columns for every project before writing. Updates tasks in one transaction, rejects project mismatches, and publishes refresh and status-change events after commit using returned task values.

apps/api/src/task/controllers/bulk-update-tasks.ts

Tests (1) +42 / -0
bulk-task-atomic-status.test.tsCover invalid destination across two projects +42/-0

Cover invalid destination across two projects

• Adds a PostgreSQL integration regression test in which the second project lacks the requested status. It verifies the request fails without changing either task or publishing events.

tests/api-integration/bulk-task-atomic-status.test.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 69e67e339d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/api/src/task/controllers/bulk-update-tasks.ts Outdated
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Task details stay stale after no-op updates ✓ Resolved
Description
bulkUpdateTasks guards task.status_changed using only before.status !== updatedTask.status,
even though the update can also change columnId and updatedAt. When a task already has the
requested status but its column assignment is stale, task-relation.refresh refreshes relations and
the board without invalidating the open task’s detail query.
Code

apps/api/src/task/controllers/bulk-update-tasks.ts[R155-157]

+        const before = tasks.find((task) => task.id === updatedTask.id)!;
+        if (before.status !== updatedTask.status)
       await publishEvent("task.status_changed", {
-            taskId: task.id,
-            projectId,
Evidence
The bulk update writes status and columnId, but its status-event guard compares only the previous
and updated status, so a same-status write can omit the per-task event. The WebSocket handler sends
a per-task update for a status event, whereas the project-wide relation refresh invalidates
relations and the board but not the individual task-detail query.

AGENTS.md: Publish and Deliver Mutation Events Across Realtime Consumers: AGENTS.md: Publish and Deliver Mutation Events Across Realtime Consumers: AGENTS.md: Publish and Deliver Mutation Events Across Realtime Consumers: AGENTS.md: Publish and Deliver Mutation Events Across Realtime Consumers: AGENTS.md: Publish and Deliver Mutation Events Across Realtime Consumers: AGENTS.md: Publish and Deliver Mutation Events Across Realtime Consumers: AGENTS.md: Publish and Deliver Mutation Events Across Realtime Consumers: AGENTS.md: Publish and Deliver Mutation Events Across Realtime Consumers
apps/api/src/task/controllers/bulk-update-tasks.ts[125-140]
apps/api/src/task/controllers/bulk-update-tasks.ts[154-170]
apps/web/src/hooks/use-project-websocket.ts[81-127]
apps/api/src/task/controllers/bulk-update-tasks.ts[125-156]
apps/api/src/ws/index.ts[418-435]
apps/api/src/ws/index.ts[507-535]
apps/web/src/hooks/use-project-websocket.ts[83-121]
apps/web/src/hooks/queries/task/use-get-task.ts[4-12]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A same-status bulk request can change a task’s persisted fields without sending the per-task update needed to refresh its details.
## Fix Focus Areas
- apps/api/src/task/controllers/bulk-update-tasks.ts[125-170]
- apps/web/src/hooks/use-project-websocket.ts[83-121]
## Recommended Fix
Ensure every row whose persisted data changes emits a per-task update, including same-status column changes, without creating an inaccurate status-change activity event. Alternatively, avoid writing rows whose status and column assignment are already correct. Preserve post-commit event ordering.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Bulk-update conflict errors lack documentation ✓ Resolved
Description
bulkUpdateTasks introduces an HTTP 409 response when a task no longer belongs to its initially
selected project, but the bulk route declares no 409 response. A concurrent project move can
therefore produce an error absent from the route contract and committed OpenAPI documentation.
Code

apps/api/src/task/controllers/bulk-update-tasks.ts[R141-144]

+          if (changed.length !== projectTaskIds.length)
+            throw new HTTPException(409, {
+              message: "Tasks changed projects; retry the operation",
+            });
Evidence
The changed controller throws HTTP 409, whereas the route response map lists only 200, 400, 403, and
404.

AGENTS.md: Keep OpenAPI Documentation Aligned With API Contracts: AGENTS.md: Keep OpenAPI Documentation Aligned With API Contracts: AGENTS.md: Keep OpenAPI Documentation Aligned With API Contracts: AGENTS.md: Keep OpenAPI Documentation Aligned With API Contracts: AGENTS.md: Keep OpenAPI Documentation Aligned With API Contracts: AGENTS.md: Keep OpenAPI Documentation Aligned With API Contracts: AGENTS.md: Keep OpenAPI Documentation Aligned With API Contracts: AGENTS.md: Keep OpenAPI Documentation Aligned With API Contracts
apps/api/src/task/controllers/bulk-update-tasks.ts[141-144]
apps/api/src/task/index.ts[136-151]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The bulk route can now return HTTP 409, but its published response contract does not include that outcome.
## Fix Focus Areas
- apps/api/src/task/index.ts[136-151]
- apps/docs/openapi.json[1-1]
## Recommended Fix
Add a 409 error response to the bulk route's OpenAPI definition and regenerate the committed OpenAPI artifact.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Large bulk requests slow down quadratically ✓ Resolved
Description
bulkUpdateTasks calls tasks.find() for each updated row to recover its previous status,
repeatedly scanning the original task snapshot. Because the request schema imposes no maximum task
count, large bulk requests make post-commit event preparation quadratic, even when all tasks belong
to one project.
Code

apps/api/src/task/controllers/bulk-update-tasks.ts[R154-155]

+      for (const updatedTask of updatedTasks) {
+        const before = tasks.find((task) => task.id === updatedTask.id)!;
Evidence
The post-commit loop performs a linear search through tasks for every row in updatedTasks, while
the request schema permits an unbounded number of task IDs. Together, these show that event
preparation adds quadratic in-memory work as bulk requests grow.

AGENTS.md: Keep Task-Heavy Boards and Realtime Updates Efficient: AGENTS.md: Keep Task-Heavy Boards and Realtime Updates Efficient: AGENTS.md: Keep Task-Heavy Boards and Realtime Updates Efficient: AGENTS.md: Keep Task-Heavy Boards and Realtime Updates Efficient: AGENTS.md: Keep Task-Heavy Boards and Realtime Updates Efficient: AGENTS.md: Keep Task-Heavy Boards and Realtime Updates Efficient: AGENTS.md: Keep Task-Heavy Boards and Realtime Updates Efficient: AGENTS.md: Keep Task-Heavy Boards and Realtime Updates Efficient
apps/api/src/task/controllers/bulk-update-tasks.ts[149-166]
apps/api/src/task/controllers/bulk-update-tasks.ts[149-161]
apps/api/src/task/schema.ts[51-63]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Per-row `tasks.find()` calls make post-commit event preparation quadratic for large bulk requests.
## Fix Focus Areas
- apps/api/src/task/controllers/bulk-update-tasks.ts[149-166]
- apps/api/src/task/schema.ts[51-63]
## Recommended Fix
Build a map of the original tasks keyed by task ID once before the event loop, then use constant-time lookups to recover each updated task's previous status while publishing events.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View high (2)
4. Bulk updates fetch unused task columns ✓ Resolved
Description
bulkUpdateTasks returns nearly every task column from each database update although its subsequent
event logic reads only the identifier, project, status, title, and assignee. For task-heavy
requests, the extra columns are transferred and retained for every updated row without contributing
to the response or events.
Code

apps/api/src/task/controllers/bulk-update-tasks.ts[R137-140]

+            .returning({
+              ...getTableColumns(taskTable),
+              description: sql<null>`null`,
+            });
Evidence
The new getTableColumns(taskTable) selection returns columns beyond those read from updatedTask
in the event loop; the task schema includes positions, dates, priority, and other unused fields.

AGENTS.md: Keep Task-Heavy Boards and Realtime Updates Efficient: AGENTS.md: Keep Task-Heavy Boards and Realtime Updates Efficient: AGENTS.md: Keep Task-Heavy Boards and Realtime Updates Efficient: AGENTS.md: Keep Task-Heavy Boards and Realtime Updates Efficient: AGENTS.md: Keep Task-Heavy Boards and Realtime Updates Efficient: AGENTS.md: Keep Task-Heavy Boards and Realtime Updates Efficient: AGENTS.md: Keep Task-Heavy Boards and Realtime Updates Efficient: AGENTS.md: Keep Task-Heavy Boards and Realtime Updates Efficient
apps/api/src/task/controllers/bulk-update-tasks.ts[137-140]
apps/api/src/task/controllers/bulk-update-tasks.ts[149-166]
apps/api/src/database/schema.ts[425-464]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The transaction returns task columns that the bulk-status response and subsequent events do not use.
## Fix Focus Areas
- apps/api/src/task/controllers/bulk-update-tasks.ts[119-140]
- apps/api/src/task/controllers/bulk-update-tasks.ts[149-166]
## Recommended Fix
Replace the full-column returning selection with the specific fields needed for the count and post-commit events.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Successful cross-project updates lack a test ✓ Resolved
Description
bulk-task-atomic-status.test.ts exercises only a destination-validation failure and asserts that
no event is published. The existing successful bulk-status test uses one project, leaving the new
multi-project commit and post-commit event sequence unverified.
Code

tests/api-integration/bulk-task-atomic-status.test.ts[R30-37]

+  await expect(
+    bulkUpdateTasks({
+      taskIds: tasks.map((task) => task.id),
+      operation: "updateStatus",
+      value: "in-progress",
+      userId: user.id,
+    }),
+  ).rejects.toThrow("Invalid status");
Evidence
The added test expects rejection and no publication; the existing event-snapshot success case
creates tasks only in a single project.

AGENTS.md: Test Affected Behavior at the Appropriate Level: AGENTS.md: Test Affected Behavior at the Appropriate Level: AGENTS.md: Test Affected Behavior at the Appropriate Level: AGENTS.md: Test Affected Behavior at the Appropriate Level: AGENTS.md: Test Affected Behavior at the Appropriate Level: AGENTS.md: Test Affected Behavior at the Appropriate Level: AGENTS.md: Test Affected Behavior at the Appropriate Level: AGENTS.md: Test Affected Behavior at the Appropriate Level
tests/api-integration/bulk-task-atomic-status.test.ts[16-42]
tests/api-integration/bulk-task-events.test.ts[18-48]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new regression test covers rejection before a write but not the successful multi-project transaction or its post-commit events.
## Fix Focus Areas
- tests/api-integration/bulk-task-atomic-status.test.ts[16-42]
## Recommended Fix
Add a PostgreSQL integration case that updates tasks in two projects, checks both persisted destinations, and verifies that the corresponding events are published after commit.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can route each severity your way: inline, summary, both, or drop

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread apps/api/src/task/controllers/bulk-update-tasks.ts Outdated
Comment thread apps/api/src/task/controllers/bulk-update-tasks.ts
Comment thread apps/api/src/task/controllers/bulk-update-tasks.ts Outdated
Comment thread apps/api/src/task/controllers/bulk-update-tasks.ts
Comment thread tests/api-integration/bulk-task-atomic-status.test.ts
@tinsever

Copy link
Copy Markdown
Member Author

@codex review

@github-actions github-actions Bot added size/m and removed size/s labels Sep 29, 2026
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Hooray!

Reviewed commit: 5a05383473

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@tinsever
tinsever changed the base branch from main to fix/review-06-integration-scope September 30, 2026 11:06
@tinsever

Copy link
Copy Markdown
Member Author

@codex review

tinsever added a commit that referenced this pull request Sep 30, 2026
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. What shall we delve into next?

Reviewed commit: 3d62ef3b2b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@tinsever
tinsever added this pull request to stack #1886 September 30, 2026 11:20
An error occurred while trying to automatically change base from fix/review-06-integration-scope to main September 30, 2026 15:55
@tinsever
tinsever removed this pull request from stack #1886 September 30, 2026 16:59
@tinsever
tinsever changed the base branch from fix/review-06-integration-scope to main September 30, 2026 16:59
@tinsever
tinsever added this pull request to stack #1888 September 30, 2026 16:59
@tinsever
tinsever merged commit e25f53a into main Sep 30, 2026
25 of 42 checks passed
@tinsever
tinsever deleted the fix/review-09-bulk-status branch September 30, 2026 17:14
github-actions Bot added a commit to capital-shield/kaneo that referenced this pull request Oct 3, 2026
### Features

- **web:** redesign settings: usekaneo#1905
- **site:** link community projects from resources: [69ba99d](69ba99d)
- **site:** add a community projects page: [961c309](961c309)
- **site:** sync product preview with home, inbox and my tasks: [30ba825](30ba825)
- missing french translation: usekaneo#1903
- add short task links like /acme/task/KAN-12: usekaneo#1891
- **web:** add home, inbox and my tasks pages: usekaneo#1898
- **web:** wire the task copy shortcuts: usekaneo#1897
- **web:** move task delete into the action group: usekaneo#1896
- **site:** add guides and retarget alternatives: [58f6d47](58f6d47)
- **web:** track the cloud signup funnel: [abacad7](abacad7)
- **docker:** support file-backed secrets for container deployments: usekaneo#1853
- sort labels alphabetically: usekaneo#1856
- **web:** select task ranges with shift-click: usekaneo#1838
- clickable task PR list, task link matching, and reopen completed tasks for new work: usekaneo#1864
- **mcp:** get tasks by ticket ID: usekaneo#1839
- **web:** guide cloud users through invites and plan choice during onboarding: usekaneo#1840
- rank new issue priority with Jev: [594e016](594e016)
- **web:** cloud sign-up and onboarding layout: usekaneo#1832
- gitlab integration: usekaneo#1727
- **tasks:** show subtask progress on cards and list rows: usekaneo#1703
- added project backgrounds: usekaneo#1654
- multiselect for customfield: usekaneo#1735
- **ci:** discord actions webhook: usekaneo#1792
- **ci:** adding zizmor: usekaneo#1790
- **project:** move a project to another workspace: usekaneo#1525
- duplicate a task from the card context menu: usekaneo#1609
- allow manual external resource links: usekaneo#1661
- **ci:** trufflehog implementation: usekaneo#1787
- **task:** let images be resized in the task description: usekaneo#1529
- **web:** add a change-password screen under account settings: usekaneo#1719
- **auth:** add password recovery from the login screen: usekaneo#1773
- add instance user administration panel: usekaneo#1400
- **site:** bring product preview up to date with current app: [dd855f7](dd855f7)
- **site:** refresh marketing site and interactive product previews: [90aec99](90aec99)
- **calendar:** add label-filtered project calendar feeds: usekaneo#1763

### Bug Fixes

- **web:** send subscription revenue as a property: [445b735](445b735)
- **site:** list GitLab with the git integrations: [3c01517](3c01517)
- **site:** serve favicon.ico: [e7ef050](e7ef050)
- **docs:** load the docs font from its real path: [22c7a02](22c7a02)
- **tasks:** make bulk status changes atomic: usekaneo#1873
- **integrations:** preserve rapid legitimate edits: usekaneo#1874
- **integrations:** enforce current task ownership: usekaneo#1867
- **ws:** revoke removed workspace members: usekaneo#1865
- **migrations:** record workflow migration completion: usekaneo#1872
- **auth:** enforce api key quotas and rate limits: usekaneo#1869
- **mcp:** share tools and support workspace label deletion: usekaneo#1871
- **reminders:** persist notification and claim atomically: usekaneo#1870
- **integrations:** require task update permission for imports: usekaneo#1868
- **ci:** publish npm provenance on GitHub-hosted runners: [50779a4](50779a4)
- **gitea:** reject saved tokens for changed servers: usekaneo#1866
- **ci:** pass the GitHub token to AgentScan: usekaneo#1862
- **ci:** resolve nightly warnings and errors: usekaneo#1858
- **api:** make legacy MCP HTTP requests replica independent: usekaneo#1850
- **docker:** disable wget proxy for loopback health checks: usekaneo#1841
- **billing:** resize Creem seats by subscription item id: usekaneo#1836
- **gitea:** prevent outbound comment echoes: usekaneo#1834
- **deps:** migrate Sentry SDKs together to v11 (usekaneo#1826): usekaneo#1826
- **ci:** grant nightly reusable CI scan permission: [0216067](0216067)
- **board:** allow column moves while sorting by task number: usekaneo#1816
- **auth:** backfill instance admin on legacy installations: [b7c6aee](b7c6aee)
- **admin:** harden the user administration panel: usekaneo#1805
- **admin:** allow updating your own email without changing role: [3d57439](3d57439)
- **security:** close permission and integration gaps: usekaneo#1802
- **project:** secure integrations across workspace moves: usekaneo#1801
- **editor:** preserve formatting when pasting Markdown: usekaneo#1797
- **auth:** report invitation email delivery failures: usekaneo#1798
- **gitea:** verify saved repository connections: usekaneo#1796
- **mcp:** keep OAuth requests valid outside UTC: usekaneo#1795
- **i18n:** translate calendar in remaining locales: [1d61ceb](1d61ceb)
- **ci:** zizmor findings: usekaneo#1791
- **integrations:** resolve PRs through linked issue identities: usekaneo#1739
- **auth:** prevent repeated 401s for pending invitations after session expiry: usekaneo#1715
- **auth:** gate sign-in emails to deliverable addresses: usekaneo#1758
- **web:** preserve image uploads across editor recreation: usekaneo#1738
- **reminders:** calculate deadlines from the end of the due day: usekaneo#1762
- **mcp:** support whoami with API keys: usekaneo#1748
- **web:** respect DISABLE_WORKSPACE_CREATION on the onboarding screen: usekaneo#1744
- **backlog:** prevent task remounts during list interactions: usekaneo#1734
- **auth:** prevent role changes from removing the last admin: usekaneo#1733
- **npm:** fixing GHSA-2xp9-vwfh-vxw4: usekaneo#1777
- **web:** guard tiptap setHardBreak against invalid-content schema error: [be3ffb5](be3ffb5)
- **i18n:** prevent locale module crash on stale dynamic import: usekaneo#1775
- **site:** improve search metadata and product discovery: [121183e](121183e)
- **web:** allow non-root runtime configuration writes: usekaneo#1767
- **site:** poof away preview cursor on interaction: [08dcaee](08dcaee)
- **nginx:** allow larger OAuth session headers: usekaneo#1761
- **deps:** resolve open dependabot advisories: [b8432a0](b8432a0)
- **web:** preserve comment markdown spacing: usekaneo#1521

### Performance Improvements

- **project:** stop returning tasks with project details: usekaneo#1800

### Documentation

- update sponsors: [1c51887](1c51887)
- add AI Policy badge to README: [011c8ee](011c8ee)
- update sponsors: [e45c8ac](e45c8ac)
- assign issue types from templates: [4725cfa](4725cfa)
- simplify issue and pull request templates: [cb6ce20](cb6ce20)
- adopt Human Voice AI contribution policy: [b090123](b090123)
- overhaul agents.md: [4d619aa](4d619aa)
- **readme:** highlight cloud and current features: usekaneo#1831
- update contributors and sponsors: [c200d70](c200d70)
- rebuild guides around current Kaneo workflows: usekaneo#1814
- acknowledge BrowserStack testing: [e389a68](e389a68)
- update contributors and sponsors: [fa07f10](fa07f10)
- **site:** add Blacksmith partner badge to site and README: [08a93b8](08a93b8)
- update contributors and sponsors: [8432a45](8432a45)
- **site:** refresh press kit with product screenshots: [3470b0a](3470b0a)
- update blog comparisons for current Kaneo features: [b97bf7d](b97bf7d)
- update contributors and sponsors: [6c7001c](6c7001c)

### Credits

Huge thanks to @tinsever, @MonsPropre, @andrejsshell, @tuttucodes, @druwan, @randoneering, @mazzz1y, @zaralX, @TymekV, @rdlugs, @tbringuier, @mohiuddin000, @shiminshen, @yavilavi, @thejdubb02, @yigit-serin, @OmG3r, and @zerodarkzone for helping!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant