dailybot-cli 3.14.3__tar.gz → 3.16.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/PKG-INFO +15 -12
  2. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/README.md +14 -11
  3. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/api_client.py +15 -15
  4. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/board.py +16 -15
  5. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/goal.py +3 -3
  6. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/project.py +20 -11
  7. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/public_api_helpers.py +20 -11
  8. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli.egg-info/PKG-INFO +15 -12
  9. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/pyproject.toml +1 -1
  10. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/LICENSE +0 -0
  11. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/__init__.py +0 -0
  12. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/__init__.py +0 -0
  13. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/_attachments.py +0 -0
  14. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/_beta.py +0 -0
  15. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/_destructive.py +0 -0
  16. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/_favorites.py +0 -0
  17. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/_rollups.py +0 -0
  18. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/_writes.py +0 -0
  19. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/agent.py +0 -0
  20. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/ask.py +0 -0
  21. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/auth.py +0 -0
  22. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/authoring_helpers.py +0 -0
  23. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/channels.py +0 -0
  24. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/chat.py +0 -0
  25. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/checkin.py +0 -0
  26. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/config.py +0 -0
  27. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/conversation.py +0 -0
  28. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/env.py +0 -0
  29. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/featured.py +0 -0
  30. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/form.py +0 -0
  31. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/hook.py +0 -0
  32. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/identity.py +0 -0
  33. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/interactive.py +0 -0
  34. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/interactive_chat.py +0 -0
  35. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/kudos.py +0 -0
  36. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/label.py +0 -0
  37. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/query_options.py +0 -0
  38. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/status.py +0 -0
  39. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/task.py +0 -0
  40. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/tasks.py +0 -0
  41. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/team.py +0 -0
  42. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/uninstall.py +0 -0
  43. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/update.py +0 -0
  44. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/upgrade.py +0 -0
  45. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/user.py +0 -0
  46. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/user_scoped_actions.py +0 -0
  47. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/version.py +0 -0
  48. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/commands/workflow.py +0 -0
  49. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/config.py +0 -0
  50. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/display.py +0 -0
  51. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/install_method.py +0 -0
  52. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/ledger.py +0 -0
  53. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/main.py +0 -0
  54. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/tui/__init__.py +0 -0
  55. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/tui/app.py +0 -0
  56. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/tui/commands.py +0 -0
  57. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/tui/conversation.py +0 -0
  58. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli/tui/intents.py +0 -0
  59. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli.egg-info/SOURCES.txt +0 -0
  60. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli.egg-info/dependency_links.txt +0 -0
  61. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli.egg-info/entry_points.txt +0 -0
  62. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli.egg-info/requires.txt +0 -0
  63. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/dailybot_cli.egg-info/top_level.txt +0 -0
  64. {dailybot_cli-3.14.3 → dailybot_cli-3.16.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dailybot-cli
3
- Version: 3.14.3
3
+ Version: 3.16.0
4
4
  Summary: Dailybot CLI - The command-line bridge between humans and agents. Progress reports, observability, and workflow automation for modern teams across Slack, Google Chat, Discord, MS Teams, and more.
5
5
  Author-email: Dailybot <support@dailybot.com>
6
6
  License: MIT
@@ -905,11 +905,13 @@ Replies to agent emails land as messages retrievable via `dailybot agent message
905
905
  Projects, boards and tasks. Two groups: **`dailybot tasks`** answers questions about the
906
906
  workspace, **`dailybot task`** reads or changes one task.
907
907
 
908
- **Structure changes need a signed-in organization admin.** Creating, updating, archiving or
909
- restoring boards, columns, projects and goals, board and project membership, and linking
910
- goals to projects all need the `tasks:admin` scope, which an organization API key can never
911
- hold. With only `DAILYBOT_API_KEY` those commands stop before sending anything; run
912
- `dailybot login` first.
908
+ **Structure changes need a signed-in person (any non-guest member).** Creating, updating,
909
+ archiving or restoring boards, columns, projects and goals, board and project membership,
910
+ and linking goals to projects all work for every non-guest member after `dailybot login`.
911
+ An organization API key can never hold `tasks:admin` and cannot change membership or
912
+ participants — with only `DAILYBOT_API_KEY` those commands stop before sending anything.
913
+ **Privacy is membership**, not org role: a `members` project or board is 404 (not visible)
914
+ to anyone without a grant; invite a person or a team to close it.
913
915
 
914
916
  The command an agent should reach for first is **`dailybot project update-post`** — it is
915
917
  how the team sees what was done. An agent that moves tasks silently is invisible to the
@@ -964,12 +966,12 @@ humans who own them.
964
966
  | `dailybot board labels <uuid>` | Labels available on the board — **needs `dailybot login`** |
965
967
  | `dailybot board views <uuid>` | Your saved views on the board, plus the ETag a save needs (`--etag` prints only that) |
966
968
  | `dailybot board state create\|update\|archive\|restore\|reorder` | Manage columns. `archive` previews first and takes `--migrate-to <state>` to move the column's cards |
967
- | `dailybot board member add <board> <user>` (or `--team <team>`) · `board member remove <board> <user>` | Who can see the board — **needs `dailybot login` as an admin**. A team grant follows the team live. There is no board role to edit |
969
+ | `dailybot board member add <board> <user>` (or `--team <team>`) · `board member remove <board> <user>` | Who can see the board — **needs `dailybot login`**. Membership is the privacy control (not org role). A team grant follows the team live. Last grant on a private board stays (`last_grant_cannot_be_removed`) |
968
970
  | `dailybot board label create <board> -n <name>` | Create an organization label from the board — **needs `dailybot login`** |
969
971
  | `dailybot board view save <board> -f views.json --if-match <etag>` | Replace your saved views (the whole list) — **needs `dailybot login`** |
970
972
  | `dailybot board snapshot <uuid>` | The whole board in one request; carries the `delta_cursor` that `tasks changes` consumes |
971
973
  | `dailybot board update <uuid>` | Name, key (the old key stays reserved), visibility, estimate scale, auto-archive, project |
972
- | `dailybot board create --name <n> --project <uuid> --key <KEY>` | Create a board in a project; the key prefixes its tasks (`DSN-1`) — **needs `dailybot login` as an admin** |
974
+ | `dailybot board create --name <n> --project <uuid> --key <KEY>` | Create a board in a project; the key prefixes its tasks (`DSN-1`) — **needs `dailybot login`** (any non-guest member) |
973
975
  | `dailybot board archive <uuid>` | Archive a board. **Cascade-archives its live tasks**, and restoring does not bring them back |
974
976
  | `dailybot board restore <uuid>` | Restore a board (cascaded tasks stay archived) |
975
977
  | `dailybot project list` | List projects (`--include progress`) |
@@ -986,7 +988,7 @@ humans who own them.
986
988
  | `dailybot project views <uuid>` · `project view save` | Your saved views; save replaces the list and requires the ETag — **needs `dailybot login`** |
987
989
  | `dailybot project milestone-create\|milestone-update\|milestone-delete` | Dated milestones; delete retires it (tasks keep pointing at it) |
988
990
  | `dailybot project archive <uuid>` | Archive a project |
989
- | `dailybot project attach <uuid> <file>` · `project attachments` · `project attachment get\|delete` | Files on a project (≤5 MiB, one request). Attaching and deleting need a signed-in admin |
991
+ | `dailybot project attach <uuid> <file>` · `project attachments` · `project attachment get\|delete` | Files on a project (≤5 MiB, one request). Attaching and deleting need `dailybot login` |
990
992
  | `dailybot goal list` | List goals (`--include` is repeatable: `--include progress --include projects`) |
991
993
  | `dailybot goal get <uuid>` | Show one goal, with its progress and linked projects (always included) |
992
994
  | `dailybot goal create --name <n> --period-start <d> --period-end <d>` | Create a goal (a dated commitment) — **needs `dailybot login`** |
@@ -994,13 +996,14 @@ humans who own them.
994
996
  | `dailybot goal restore <uuid>` | Restore an archived goal |
995
997
  | `dailybot goal link\|unlink <goal> <project>` | Make a project count toward a goal (or stop it) |
996
998
  | `dailybot goal archive <uuid>` | Archive a goal (its projects are not archived) |
997
- | `dailybot goal attach <uuid> <file>` · `goal attachments` · `goal attachment get\|delete` | Files on a goal (≤5 MiB, one request). Attaching and deleting need a signed-in admin |
999
+ | `dailybot goal attach <uuid> <file>` · `goal attachments` · `goal attachment get\|delete` | Files on a goal (≤5 MiB, one request). Attaching and deleting need `dailybot login` |
998
1000
 
999
1001
  **Three things worth knowing before you script against this:**
1000
1002
 
1001
1003
  - **Some doors need a person.** An organization API key has no answer for "my tasks" or
1002
- "my inbox", and it can never hold `tasks:admin` — so container creates need
1003
- `dailybot login`. This is true even for an organization admin's own key.
1004
+ "my inbox", can never hold `tasks:admin`, and cannot change membership or participants —
1005
+ so container creates and invites need `dailybot login` as a non-guest member. A 404 means
1006
+ not visible (wrong id, private without a grant, or another org) — never "not allowed".
1004
1007
  - **Roll-ups are opt-in.** A field you did not request with `--include` is **absent** from
1005
1008
  the payload. Absent, `null` and `0` are three different answers, and the CLI renders them
1006
1009
  as three different things.
@@ -866,11 +866,13 @@ Replies to agent emails land as messages retrievable via `dailybot agent message
866
866
  Projects, boards and tasks. Two groups: **`dailybot tasks`** answers questions about the
867
867
  workspace, **`dailybot task`** reads or changes one task.
868
868
 
869
- **Structure changes need a signed-in organization admin.** Creating, updating, archiving or
870
- restoring boards, columns, projects and goals, board and project membership, and linking
871
- goals to projects all need the `tasks:admin` scope, which an organization API key can never
872
- hold. With only `DAILYBOT_API_KEY` those commands stop before sending anything; run
873
- `dailybot login` first.
869
+ **Structure changes need a signed-in person (any non-guest member).** Creating, updating,
870
+ archiving or restoring boards, columns, projects and goals, board and project membership,
871
+ and linking goals to projects all work for every non-guest member after `dailybot login`.
872
+ An organization API key can never hold `tasks:admin` and cannot change membership or
873
+ participants — with only `DAILYBOT_API_KEY` those commands stop before sending anything.
874
+ **Privacy is membership**, not org role: a `members` project or board is 404 (not visible)
875
+ to anyone without a grant; invite a person or a team to close it.
874
876
 
875
877
  The command an agent should reach for first is **`dailybot project update-post`** — it is
876
878
  how the team sees what was done. An agent that moves tasks silently is invisible to the
@@ -925,12 +927,12 @@ humans who own them.
925
927
  | `dailybot board labels <uuid>` | Labels available on the board — **needs `dailybot login`** |
926
928
  | `dailybot board views <uuid>` | Your saved views on the board, plus the ETag a save needs (`--etag` prints only that) |
927
929
  | `dailybot board state create\|update\|archive\|restore\|reorder` | Manage columns. `archive` previews first and takes `--migrate-to <state>` to move the column's cards |
928
- | `dailybot board member add <board> <user>` (or `--team <team>`) · `board member remove <board> <user>` | Who can see the board — **needs `dailybot login` as an admin**. A team grant follows the team live. There is no board role to edit |
930
+ | `dailybot board member add <board> <user>` (or `--team <team>`) · `board member remove <board> <user>` | Who can see the board — **needs `dailybot login`**. Membership is the privacy control (not org role). A team grant follows the team live. Last grant on a private board stays (`last_grant_cannot_be_removed`) |
929
931
  | `dailybot board label create <board> -n <name>` | Create an organization label from the board — **needs `dailybot login`** |
930
932
  | `dailybot board view save <board> -f views.json --if-match <etag>` | Replace your saved views (the whole list) — **needs `dailybot login`** |
931
933
  | `dailybot board snapshot <uuid>` | The whole board in one request; carries the `delta_cursor` that `tasks changes` consumes |
932
934
  | `dailybot board update <uuid>` | Name, key (the old key stays reserved), visibility, estimate scale, auto-archive, project |
933
- | `dailybot board create --name <n> --project <uuid> --key <KEY>` | Create a board in a project; the key prefixes its tasks (`DSN-1`) — **needs `dailybot login` as an admin** |
935
+ | `dailybot board create --name <n> --project <uuid> --key <KEY>` | Create a board in a project; the key prefixes its tasks (`DSN-1`) — **needs `dailybot login`** (any non-guest member) |
934
936
  | `dailybot board archive <uuid>` | Archive a board. **Cascade-archives its live tasks**, and restoring does not bring them back |
935
937
  | `dailybot board restore <uuid>` | Restore a board (cascaded tasks stay archived) |
936
938
  | `dailybot project list` | List projects (`--include progress`) |
@@ -947,7 +949,7 @@ humans who own them.
947
949
  | `dailybot project views <uuid>` · `project view save` | Your saved views; save replaces the list and requires the ETag — **needs `dailybot login`** |
948
950
  | `dailybot project milestone-create\|milestone-update\|milestone-delete` | Dated milestones; delete retires it (tasks keep pointing at it) |
949
951
  | `dailybot project archive <uuid>` | Archive a project |
950
- | `dailybot project attach <uuid> <file>` · `project attachments` · `project attachment get\|delete` | Files on a project (≤5 MiB, one request). Attaching and deleting need a signed-in admin |
952
+ | `dailybot project attach <uuid> <file>` · `project attachments` · `project attachment get\|delete` | Files on a project (≤5 MiB, one request). Attaching and deleting need `dailybot login` |
951
953
  | `dailybot goal list` | List goals (`--include` is repeatable: `--include progress --include projects`) |
952
954
  | `dailybot goal get <uuid>` | Show one goal, with its progress and linked projects (always included) |
953
955
  | `dailybot goal create --name <n> --period-start <d> --period-end <d>` | Create a goal (a dated commitment) — **needs `dailybot login`** |
@@ -955,13 +957,14 @@ humans who own them.
955
957
  | `dailybot goal restore <uuid>` | Restore an archived goal |
956
958
  | `dailybot goal link\|unlink <goal> <project>` | Make a project count toward a goal (or stop it) |
957
959
  | `dailybot goal archive <uuid>` | Archive a goal (its projects are not archived) |
958
- | `dailybot goal attach <uuid> <file>` · `goal attachments` · `goal attachment get\|delete` | Files on a goal (≤5 MiB, one request). Attaching and deleting need a signed-in admin |
960
+ | `dailybot goal attach <uuid> <file>` · `goal attachments` · `goal attachment get\|delete` | Files on a goal (≤5 MiB, one request). Attaching and deleting need `dailybot login` |
959
961
 
960
962
  **Three things worth knowing before you script against this:**
961
963
 
962
964
  - **Some doors need a person.** An organization API key has no answer for "my tasks" or
963
- "my inbox", and it can never hold `tasks:admin` — so container creates need
964
- `dailybot login`. This is true even for an organization admin's own key.
965
+ "my inbox", can never hold `tasks:admin`, and cannot change membership or participants —
966
+ so container creates and invites need `dailybot login` as a non-guest member. A 404 means
967
+ not visible (wrong id, private without a grant, or another org) — never "not allowed".
965
968
  - **Roll-ups are opt-in.** A field you did not request with `--include` is **absent** from
966
969
  the payload. Absent, `null` and `0` are three different answers, and the CLI renders them
967
970
  as three different things.
@@ -2574,7 +2574,7 @@ class DailyBotClient:
2574
2574
  team_uuid: str | None = None,
2575
2575
  idempotency_key: str | None = None,
2576
2576
  ) -> Any:
2577
- """POST …/members/ — `tasks:admin`; a person OR a whole team; 200 when already in.
2577
+ """POST …/members/ — person session (keys cannot change membership); 200 when already in.
2578
2578
 
2579
2579
  The body carries exactly one of `user_uuid` / `team_uuid` (both or neither is
2580
2580
  a 400 `invalid_filter_value`).
@@ -3212,7 +3212,7 @@ class DailyBotClient:
3212
3212
  self._comment_parent(task_uuid, comment_uuid), attachment_uuid
3213
3213
  )
3214
3214
 
3215
- # Project (POST / DELETE: tasks:admin, a signed-in person; reads: anyone who can see it)
3215
+ # Project attachments (POST / DELETE: signed-in person; reads: anyone who can see it)
3216
3216
  def upload_project_attachment(
3217
3217
  self,
3218
3218
  project_uuid: str,
@@ -3222,7 +3222,7 @@ class DailyBotClient:
3222
3222
  data: bytes,
3223
3223
  caption: str | None = None,
3224
3224
  ) -> dict[str, Any]:
3225
- """POST /v1/tasks/projects/<p>/attachments/ — multipart, ≤5 MiB, tasks:admin."""
3225
+ """POST /v1/tasks/projects/<p>/attachments/ — multipart, ≤5 MiB, person session."""
3226
3226
  return self._upload_attachment_to(
3227
3227
  self._project_parent(project_uuid),
3228
3228
  filename=filename,
@@ -3236,14 +3236,14 @@ class DailyBotClient:
3236
3236
  return self._list_attachments_of(self._project_parent(project_uuid))
3237
3237
 
3238
3238
  def delete_project_attachment(self, project_uuid: str, attachment_uuid: str) -> Any:
3239
- """DELETE /v1/tasks/projects/<p>/attachments/<a>/ — tasks:admin."""
3239
+ """DELETE /v1/tasks/projects/<p>/attachments/<a>/ — person session."""
3240
3240
  return self._delete_attachment_of(self._project_parent(project_uuid), attachment_uuid)
3241
3241
 
3242
3242
  def download_project_attachment(self, project_uuid: str, attachment_uuid: str) -> bytes:
3243
3243
  """GET /v1/tasks/projects/<p>/attachments/<a>/content/."""
3244
3244
  return self._download_attachment_of(self._project_parent(project_uuid), attachment_uuid)
3245
3245
 
3246
- # Goal (POST / DELETE: tasks:admin, a signed-in person; reads: anyone who can see it)
3246
+ # Goal attachments (POST / DELETE: signed-in person; reads: anyone who can see it)
3247
3247
  def upload_goal_attachment(
3248
3248
  self,
3249
3249
  goal_uuid: str,
@@ -3253,7 +3253,7 @@ class DailyBotClient:
3253
3253
  data: bytes,
3254
3254
  caption: str | None = None,
3255
3255
  ) -> dict[str, Any]:
3256
- """POST /v1/tasks/goals/<g>/attachments/ — multipart, ≤5 MiB, tasks:admin."""
3256
+ """POST /v1/tasks/goals/<g>/attachments/ — multipart, ≤5 MiB, person session."""
3257
3257
  return self._upload_attachment_to(
3258
3258
  self._goal_parent(goal_uuid),
3259
3259
  filename=filename,
@@ -3267,7 +3267,7 @@ class DailyBotClient:
3267
3267
  return self._list_attachments_of(self._goal_parent(goal_uuid))
3268
3268
 
3269
3269
  def delete_goal_attachment(self, goal_uuid: str, attachment_uuid: str) -> Any:
3270
- """DELETE /v1/tasks/goals/<g>/attachments/<a>/ — tasks:admin."""
3270
+ """DELETE /v1/tasks/goals/<g>/attachments/<a>/ — person session."""
3271
3271
  return self._delete_attachment_of(self._goal_parent(goal_uuid), attachment_uuid)
3272
3272
 
3273
3273
  def download_goal_attachment(self, goal_uuid: str, attachment_uuid: str) -> bytes:
@@ -3446,7 +3446,7 @@ class DailyBotClient:
3446
3446
  def update_project(
3447
3447
  self, project_uuid: str, *, idempotency_key: str | None = None, **fields: Any
3448
3448
  ) -> dict[str, Any]:
3449
- """PATCH /v1/tasks/projects/<uuid>/ — partial; `tasks:admin`; accepts a key."""
3449
+ """PATCH /v1/tasks/projects/<uuid>/ — partial; person session. Visibility persists; privatizing auto-grants the actor."""
3450
3450
  result: dict[str, Any] = self._tasks_write(
3451
3451
  "PATCH",
3452
3452
  f"projects/{_path_segment(project_uuid)}/",
@@ -3617,15 +3617,15 @@ class DailyBotClient:
3617
3617
 
3618
3618
  # --- Container writes (board / project / goal) ---
3619
3619
  #
3620
- # These need `tasks:admin`, which an organization API key can NEVER hold: the
3621
- # validator refuses to store it and the door refuses it independently. The
3622
- # plan's live probe measured an ADMIN_ORG *owner* refused identically, so the
3623
- # CLI must blame the credential kind rather than the user's role.
3620
+ # Open-org Tasks: every non-guest member holds `tasks:admin` on a person
3621
+ # session. An organization API key can NEVER store that scope, so the CLI
3622
+ # refuses a key before the request and blames the credential kind. Membership
3623
+ # and participant writes stay person-only too.
3624
3624
 
3625
3625
  def create_board(
3626
3626
  self, *, name: str, idempotency_key: str | None = None, **fields: Any
3627
3627
  ) -> dict[str, Any]:
3628
- """POST /v1/tasks/boards/ — accepts a key header; needs tasks:admin."""
3628
+ """POST /v1/tasks/boards/ — person session; keys lack tasks:admin."""
3629
3629
  payload: dict[str, Any] = {
3630
3630
  "name": name,
3631
3631
  **{k: v for k, v in fields.items() if v is not None},
@@ -3677,7 +3677,7 @@ class DailyBotClient:
3677
3677
  def create_project(
3678
3678
  self, *, name: str, idempotency_key: str | None = None, **fields: Any
3679
3679
  ) -> dict[str, Any]:
3680
- """POST /v1/tasks/projects/ — accepts a key header; needs tasks:admin."""
3680
+ """POST /v1/tasks/projects/ — person session; keys lack tasks:admin."""
3681
3681
  payload: dict[str, Any] = {
3682
3682
  "name": name,
3683
3683
  **{k: v for k, v in fields.items() if v is not None},
@@ -3701,7 +3701,7 @@ class DailyBotClient:
3701
3701
  def create_goal(
3702
3702
  self, *, name: str, idempotency_key: str | None = None, **fields: Any
3703
3703
  ) -> dict[str, Any]:
3704
- """POST /v1/tasks/goals/ — accepts a key header; needs tasks:admin."""
3704
+ """POST /v1/tasks/goals/ — person session; keys lack tasks:admin."""
3705
3705
  payload: dict[str, Any] = {
3706
3706
  "name": name,
3707
3707
  **{k: v for k, v in fields.items() if v is not None},
@@ -695,11 +695,13 @@ _MEMBER_WRITE_REASON: str = (
695
695
 
696
696
  @board.group("member")
697
697
  def board_member() -> None:
698
- """Add or remove the people who can see a board. Needs `dailybot login`.
698
+ """Invite or remove who can see a board. Needs `dailybot login`.
699
699
 
700
700
  \b
701
- There is no board-level role: organization roles plus board visibility are the
702
- whole access model, so a membership can be added or removed but not edited.
701
+ Membership is the privacy control: a `members` board is invisible (404) to
702
+ anyone without a grant. Org-wide boards are a shared workspace. There is no
703
+ board-level role to edit — invite or remove only. An organization API key
704
+ cannot change membership.
703
705
 
704
706
  \b
705
707
  Examples:
@@ -965,20 +967,19 @@ def board_snapshot(board_uuid: str, json_mode: bool) -> None:
965
967
 
966
968
 
967
969
  def _require_person_for_admin(action: str, *, json_mode: bool) -> None:
968
- """Refuse a key on a door that needs `tasks:admin`.
970
+ """Refuse an organization API key on a structure or membership door.
969
971
 
970
- The scope cannot be granted to an API key at all — the validator refuses to
971
- store it, and the door refuses it independently. The plan's live probe measured
972
- an `ADMIN_ORG` **owner** refused exactly like a member, so the message must
973
- blame the **credential kind**. Telling an organization admin they "need to be an
974
- admin" would send them looking for a setting that cannot exist.
972
+ Open-org Tasks: every non-guest member holds `tasks:admin` on a person session,
973
+ so the CLI never asks for an organization-admin role. An organization API key
974
+ still cannot store that scope (or change membership / participants), so the
975
+ message blames the **credential kind** — run `dailybot login` as a member.
975
976
  """
976
977
  # See tasks.py `_require_person`: gate on the absence of a person token.
977
978
  if get_token() is None:
978
979
  refuse_without_person(
979
- f"`{action}` needs the `tasks:admin` scope, which an organization API key can "
980
- "never hold — it cannot even be stored on one. Run `dailybot login` and retry "
981
- "as a signed-in person.",
980
+ f"`{action}` needs a signed-in person. An organization API key can never hold "
981
+ "the `tasks:admin` scope (it cannot even be stored on one), and keys cannot "
982
+ "change membership. Run `dailybot login` and retry as a non-guest member.",
982
983
  json_mode=json_mode,
983
984
  admin=True,
984
985
  )
@@ -1011,11 +1012,11 @@ def board_create(
1011
1012
  idempotency_key: str | None,
1012
1013
  json_mode: bool,
1013
1014
  ) -> None:
1014
- """Create a board in a project. Needs a signed-in organization admin.
1015
+ """Create a board in a project. Needs a signed-in person (any non-guest member).
1015
1016
 
1016
1017
  \b
1017
- An organization API key cannot do this: the `tasks:admin` scope it requires can
1018
- never be held by a key. Run `dailybot login` first.
1018
+ An organization API key cannot do this — run `dailybot login` first. Visibility
1019
+ and who can see the board are controlled by invite/remove, not by org role.
1019
1020
 
1020
1021
  \b
1021
1022
  Examples:
@@ -429,7 +429,7 @@ def goal_unlink(
429
429
 
430
430
  # ---------------------------------------------------------------------------
431
431
  # Attachments. Reading needs only visibility; attaching and deleting are
432
- # `tasks:admin` doors, which refuse an organization API key before any request.
432
+ # Structure doors: refuse an organization API key before any request (keys lack tasks:admin).
433
433
  # ---------------------------------------------------------------------------
434
434
 
435
435
 
@@ -443,7 +443,7 @@ def goal_unlink(
443
443
  @click.option("--caption", default=None, help="Short caption shown with the file.")
444
444
  @click.option("--json", "json_mode", is_flag=True, help="Emit machine-readable JSON to stdout.")
445
445
  def goal_attach(goal_uuid: str, file_path: Path, caption: str | None, json_mode: bool) -> None:
446
- """Attach a file to a goal. Needs a signed-in organization admin.
446
+ """Attach a file to a goal. Needs a signed-in person (any non-guest member).
447
447
 
448
448
  \b
449
449
  One request, up to 5 MiB. Your Dailybot credentials go only to the API.
@@ -535,7 +535,7 @@ def goal_attachment_get(
535
535
  def goal_attachment_delete(
536
536
  goal_uuid: str, attachment_uuid: str, dry_run: bool, assume_yes: bool, json_mode: bool
537
537
  ) -> None:
538
- """Remove an attachment from a goal. This cannot be undone. Needs an admin.
538
+ """Remove an attachment from a goal. This cannot be undone. Needs a signed-in person.
539
539
 
540
540
  \b
541
541
  Examples:
@@ -382,13 +382,17 @@ def project_milestone_reopen(
382
382
 
383
383
 
384
384
  def _require_person_for_admin(action: str, *, json_mode: bool) -> None:
385
- """Refuse a key on a `tasks:admin` door — see board.py for the full reasoning."""
385
+ """Refuse an organization API key on a structure or membership door.
386
+
387
+ See board.py: open-org Tasks gives every non-guest member structure access on
388
+ a person session; keys still cannot store `tasks:admin` or change membership.
389
+ """
386
390
  # See tasks.py `_require_person`: gate on the absence of a person token.
387
391
  if get_token() is None:
388
392
  refuse_without_person(
389
- f"`{action}` needs the `tasks:admin` scope, which an organization API key can "
390
- "never hold — it cannot even be stored on one. Run `dailybot login` and retry "
391
- "as a signed-in person.",
393
+ f"`{action}` needs a signed-in person. An organization API key can never hold "
394
+ "the `tasks:admin` scope (it cannot even be stored on one), and keys cannot "
395
+ "change membership. Run `dailybot login` and retry as a non-guest member.",
392
396
  json_mode=json_mode,
393
397
  admin=True,
394
398
  )
@@ -538,8 +542,10 @@ def project_update(
538
542
  """Change a project's name, lead, health, dates or visibility.
539
543
 
540
544
  \b
541
- Only the fields you pass are sent. Needs the `tasks:admin` scope. To post a
542
- status note for the team, use `dailybot project update-post` instead.
545
+ Only the fields you pass are sent. Any signed-in non-guest member can update;
546
+ an organization API key cannot. Setting `--visibility members` privatizes the
547
+ project and auto-grants you; invite others with `project member add`. To post
548
+ a status note for the team, use `dailybot project update-post` instead.
543
549
 
544
550
  \b
545
551
  Examples:
@@ -657,8 +663,11 @@ def project_member() -> None:
657
663
  """Invite or remove people and teams on a project. Needs `dailybot login`.
658
664
 
659
665
  \b
660
- There is no project role to edit: organization roles plus visibility are the
661
- access model.
666
+ Membership is the privacy control: a `members` project is not visible (404)
667
+ to anyone without a grant. Org-wide projects are a shared workspace. Invite a
668
+ person or a team to close a private project; the last grant cannot be removed
669
+ (`last_grant_cannot_be_removed`). There is no project role to edit. An
670
+ organization API key cannot change membership.
662
671
 
663
672
  \b
664
673
  Examples:
@@ -970,7 +979,7 @@ def project_milestone_delete(
970
979
 
971
980
  # ---------------------------------------------------------------------------
972
981
  # Attachments. Reading needs only visibility; attaching and deleting are
973
- # `tasks:admin` doors, which refuse an organization API key before any request.
982
+ # Structure doors: refuse an organization API key before any request (keys lack tasks:admin).
974
983
  # ---------------------------------------------------------------------------
975
984
 
976
985
 
@@ -986,7 +995,7 @@ def project_milestone_delete(
986
995
  def project_attach(
987
996
  project_uuid: str, file_path: Path, caption: str | None, json_mode: bool
988
997
  ) -> None:
989
- """Attach a file to a project. Needs a signed-in organization admin.
998
+ """Attach a file to a project. Needs a signed-in person (any non-guest member).
990
999
 
991
1000
  \b
992
1001
  One request, up to 5 MiB. Your Dailybot credentials go only to the API.
@@ -1078,7 +1087,7 @@ def project_attachment_get(
1078
1087
  def project_attachment_delete(
1079
1088
  project_uuid: str, attachment_uuid: str, dry_run: bool, assume_yes: bool, json_mode: bool
1080
1089
  ) -> None:
1081
- """Remove an attachment from a project. This cannot be undone. Needs an admin.
1090
+ """Remove an attachment from a project. This cannot be undone. Needs a signed-in person.
1082
1091
 
1083
1092
  \b
1084
1093
  Examples:
@@ -165,8 +165,12 @@ ERROR_CODE_MESSAGES: dict[str, str] = {
165
165
  "there — do not send this one again."
166
166
  ),
167
167
  # Isolation: 404 for anything invisible, never 403. Saying "permission" here
168
- # would both mislead and disclose that the object exists.
169
- "not_found": "Not found. Check the identifier, or it may belong to another organization.",
168
+ # would both mislead and disclose that the object exists. Membership-private
169
+ # projects/boards report the same way — treat 404 as not visible, not not allowed.
170
+ "not_found": (
171
+ "Not found or not visible to you. Check the identifier, invite status, or it may "
172
+ "belong to another organization."
173
+ ),
170
174
  "form_response_change_state_forbidden": (
171
175
  "You don't have permission to change the state of this submission. "
172
176
  "The form's audience may restrict transitions to specific users / teams. "
@@ -579,10 +583,13 @@ _PERSON_SHAPED_GUIDANCE: str = (
579
583
  "to be. Run `dailybot login` and retry."
580
584
  )
581
585
 
586
+ # Keys still cannot store `tasks:admin`. Every non-guest member holds it on a
587
+ # person session, so structure creates/updates go through `dailybot login` — not
588
+ # an organization-admin role check in the CLI.
582
589
  _ADMIN_SCOPE_GUIDANCE: str = (
583
- "This action needs the `tasks:admin` scope, which an organization API key can never "
584
- "hold — it cannot even be stored on one. Run `dailybot login` and retry as a signed-in "
585
- "person."
590
+ "This action needs a signed-in person: an organization API key can never hold the "
591
+ "`tasks:admin` scope (it cannot even be stored on one). Run `dailybot login` and retry "
592
+ "as a non-guest member. Membership and participant changes stay person-only too."
586
593
  )
587
594
 
588
595
 
@@ -686,14 +693,16 @@ def resolve_error_message(
686
693
  if exc.code == "insufficient_scope":
687
694
  required: Any = (exc.extra or {}).get("required_scope")
688
695
  if required == "tasks:admin":
689
- # The "a key can never hold this" sentence is only true of a key. A
690
- # signed-in member hitting the same refusal needs a role, not another
691
- # login — telling them to `dailybot login` sends them in a circle.
696
+ # Open-org Tasks: every non-guest member already holds tasks:admin.
697
+ # A signed-in refusal is almost always a guest (or another role without
698
+ # structure access) — never "ask an admin to grant admin". Keys still
699
+ # cannot store the scope at all.
692
700
  if get_token() is not None:
693
701
  return (
694
- "This action needs the `tasks:admin` scope and your account does not "
695
- "hold it. This is a role limit, not a credential problem — ask an "
696
- "organization admin to grant it. Signing in again will not change it."
702
+ "Your account cannot change Tasks structure. Guests are refused; every "
703
+ "non-guest member can create and manage goals, projects, boards and "
704
+ "memberships. This is a role limit, not a credential problem — signing "
705
+ "in again will not change it."
697
706
  )
698
707
  return _ADMIN_SCOPE_GUIDANCE
699
708
  if tasks_surface and get_token() is None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dailybot-cli
3
- Version: 3.14.3
3
+ Version: 3.16.0
4
4
  Summary: Dailybot CLI - The command-line bridge between humans and agents. Progress reports, observability, and workflow automation for modern teams across Slack, Google Chat, Discord, MS Teams, and more.
5
5
  Author-email: Dailybot <support@dailybot.com>
6
6
  License: MIT
@@ -905,11 +905,13 @@ Replies to agent emails land as messages retrievable via `dailybot agent message
905
905
  Projects, boards and tasks. Two groups: **`dailybot tasks`** answers questions about the
906
906
  workspace, **`dailybot task`** reads or changes one task.
907
907
 
908
- **Structure changes need a signed-in organization admin.** Creating, updating, archiving or
909
- restoring boards, columns, projects and goals, board and project membership, and linking
910
- goals to projects all need the `tasks:admin` scope, which an organization API key can never
911
- hold. With only `DAILYBOT_API_KEY` those commands stop before sending anything; run
912
- `dailybot login` first.
908
+ **Structure changes need a signed-in person (any non-guest member).** Creating, updating,
909
+ archiving or restoring boards, columns, projects and goals, board and project membership,
910
+ and linking goals to projects all work for every non-guest member after `dailybot login`.
911
+ An organization API key can never hold `tasks:admin` and cannot change membership or
912
+ participants — with only `DAILYBOT_API_KEY` those commands stop before sending anything.
913
+ **Privacy is membership**, not org role: a `members` project or board is 404 (not visible)
914
+ to anyone without a grant; invite a person or a team to close it.
913
915
 
914
916
  The command an agent should reach for first is **`dailybot project update-post`** — it is
915
917
  how the team sees what was done. An agent that moves tasks silently is invisible to the
@@ -964,12 +966,12 @@ humans who own them.
964
966
  | `dailybot board labels <uuid>` | Labels available on the board — **needs `dailybot login`** |
965
967
  | `dailybot board views <uuid>` | Your saved views on the board, plus the ETag a save needs (`--etag` prints only that) |
966
968
  | `dailybot board state create\|update\|archive\|restore\|reorder` | Manage columns. `archive` previews first and takes `--migrate-to <state>` to move the column's cards |
967
- | `dailybot board member add <board> <user>` (or `--team <team>`) · `board member remove <board> <user>` | Who can see the board — **needs `dailybot login` as an admin**. A team grant follows the team live. There is no board role to edit |
969
+ | `dailybot board member add <board> <user>` (or `--team <team>`) · `board member remove <board> <user>` | Who can see the board — **needs `dailybot login`**. Membership is the privacy control (not org role). A team grant follows the team live. Last grant on a private board stays (`last_grant_cannot_be_removed`) |
968
970
  | `dailybot board label create <board> -n <name>` | Create an organization label from the board — **needs `dailybot login`** |
969
971
  | `dailybot board view save <board> -f views.json --if-match <etag>` | Replace your saved views (the whole list) — **needs `dailybot login`** |
970
972
  | `dailybot board snapshot <uuid>` | The whole board in one request; carries the `delta_cursor` that `tasks changes` consumes |
971
973
  | `dailybot board update <uuid>` | Name, key (the old key stays reserved), visibility, estimate scale, auto-archive, project |
972
- | `dailybot board create --name <n> --project <uuid> --key <KEY>` | Create a board in a project; the key prefixes its tasks (`DSN-1`) — **needs `dailybot login` as an admin** |
974
+ | `dailybot board create --name <n> --project <uuid> --key <KEY>` | Create a board in a project; the key prefixes its tasks (`DSN-1`) — **needs `dailybot login`** (any non-guest member) |
973
975
  | `dailybot board archive <uuid>` | Archive a board. **Cascade-archives its live tasks**, and restoring does not bring them back |
974
976
  | `dailybot board restore <uuid>` | Restore a board (cascaded tasks stay archived) |
975
977
  | `dailybot project list` | List projects (`--include progress`) |
@@ -986,7 +988,7 @@ humans who own them.
986
988
  | `dailybot project views <uuid>` · `project view save` | Your saved views; save replaces the list and requires the ETag — **needs `dailybot login`** |
987
989
  | `dailybot project milestone-create\|milestone-update\|milestone-delete` | Dated milestones; delete retires it (tasks keep pointing at it) |
988
990
  | `dailybot project archive <uuid>` | Archive a project |
989
- | `dailybot project attach <uuid> <file>` · `project attachments` · `project attachment get\|delete` | Files on a project (≤5 MiB, one request). Attaching and deleting need a signed-in admin |
991
+ | `dailybot project attach <uuid> <file>` · `project attachments` · `project attachment get\|delete` | Files on a project (≤5 MiB, one request). Attaching and deleting need `dailybot login` |
990
992
  | `dailybot goal list` | List goals (`--include` is repeatable: `--include progress --include projects`) |
991
993
  | `dailybot goal get <uuid>` | Show one goal, with its progress and linked projects (always included) |
992
994
  | `dailybot goal create --name <n> --period-start <d> --period-end <d>` | Create a goal (a dated commitment) — **needs `dailybot login`** |
@@ -994,13 +996,14 @@ humans who own them.
994
996
  | `dailybot goal restore <uuid>` | Restore an archived goal |
995
997
  | `dailybot goal link\|unlink <goal> <project>` | Make a project count toward a goal (or stop it) |
996
998
  | `dailybot goal archive <uuid>` | Archive a goal (its projects are not archived) |
997
- | `dailybot goal attach <uuid> <file>` · `goal attachments` · `goal attachment get\|delete` | Files on a goal (≤5 MiB, one request). Attaching and deleting need a signed-in admin |
999
+ | `dailybot goal attach <uuid> <file>` · `goal attachments` · `goal attachment get\|delete` | Files on a goal (≤5 MiB, one request). Attaching and deleting need `dailybot login` |
998
1000
 
999
1001
  **Three things worth knowing before you script against this:**
1000
1002
 
1001
1003
  - **Some doors need a person.** An organization API key has no answer for "my tasks" or
1002
- "my inbox", and it can never hold `tasks:admin` — so container creates need
1003
- `dailybot login`. This is true even for an organization admin's own key.
1004
+ "my inbox", can never hold `tasks:admin`, and cannot change membership or participants —
1005
+ so container creates and invites need `dailybot login` as a non-guest member. A 404 means
1006
+ not visible (wrong id, private without a grant, or another org) — never "not allowed".
1004
1007
  - **Roll-ups are opt-in.** A field you did not request with `--include` is **absent** from
1005
1008
  the payload. Absent, `null` and `0` are three different answers, and the CLI renders them
1006
1009
  as three different things.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "dailybot-cli"
7
- version = "3.14.3"
7
+ version = "3.16.0"
8
8
  description = "Dailybot CLI - The command-line bridge between humans and agents. Progress reports, observability, and workflow automation for modern teams across Slack, Google Chat, Discord, MS Teams, and more."
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
File without changes
File without changes