How projects actually behave, and how I name them #323
ianTPE
started this conversation in
Show and tell
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
I spent a while working out how to name projects, and ended up reading the source to
answer questions the docs don't cover yet. Posting what I found, plus the conventions I
settled on, in case it saves someone else the trip.
What a project actually is
A project isn't a folder or a task list. It's a scope —
group:web-project-<uuid>—and a scope owns its own memory, files, keychain view, crons, and durable sandbox. A
Slack channel is a scope too (
channel:<id>), and so is your personal space. They sitside by side. Nothing nests inside anything else.
Five things follow from that, and all five changed how I name things.
Opening a new project starts fresh — with one deliberate exception. New scope means
new memory, new files, a fresh sandbox, and no credential grants. Skills are the
exception, and the intended carrier: they resolve across an ordered scope chain, so
anything you
promoteto a team or org scope is available in every project you openlater, unless a same-named skill in the project shadows it. Memory and files don't travel
that way — if something is worth reusing, make it a skill rather than reopening the
project.
Names aren't unique and nothing warns you.
createonly checks that the name isnon-empty. Two projects can have the same name and coexist quietly.
The name is display-only. Identity is the UUID in the scope id, and nothing resolves
a project by name. So renaming is safe — it doesn't move the scope, break links, or touch
memory, files, or grants.
The list is per-member and sorted by recency, never alphabetically.
listForMemberreturns only projects you belong to, and there's no org-wide project directory. The web
UI groups personal → projects → channels and keeps the server's recency order inside each
group. So prefix schemes that rely on alphabetical grouping buy you nothing here. The
search box does a case-insensitive substring match over the title and subtitle, which
means a keyword works no matter where it sits in the name.
Changing the roster has side effects that renaming doesn't. Adding or removing a
member bumps the project's
updatedAt, which is whatversion()returns, and pendingcapability approvals are checked against that version. Renaming doesn't bump it.
Projects and Slack channels are siblings, not parent and child
A channel is a scope too —
channel:<id>— and it sits next to projects rather thanabove them. There's no link between the two: neither side has a field referencing the
other, and there's no API to attach a channel to a project. They keep separate memory,
separate files, and separate rosters — a channel's members come from Slack, a project's
are a list you maintain yourself.
For naming, that mostly means one thing: don't name a project after a channel. Calling a
project
#proj-qm-localsuggests a connection to the channel of that name, and thereisn't one.
One asymmetry cost me some time. Standing orders only do anything on the Slack side.
Ambient judgment runs from
ingestSurfaceEvents, which is fed by a surface pushingmessages into the core, so it only ever runs for containers that come from a surface. A
project conversation isn't one — every message you post there is a turn request directly,
with no "should I respond to this" step in front of it. Projects always answer.
The catch is that nothing tells you that.
ambientPolicyAppliesreturns true for anygroup:scope, and a project scope isgroup:web-project-<uuid>, so the standing-ordereditor renders in a project's settings panel, and
setContextPolicyaccepts the write.It saves, it reports success, and nothing ever reads it back. If you're trying to get a
project to act on its own, that isn't the knob.
What that means for naming
One long-lived project per recurring thing, not one per cycle.
Don't open "August close" and then "September close". Open "Monthly close" and do it
again each month inside. A new project each cycle throws away the accumulated memory, the
sandbox state, and the credential grants. Put the period in the session, not the project.
Dates belong in a project name only when the work genuinely ends and you'll revoke access
afterwards — an annual audit, a due diligence room, a migration.
Use words you'd actually type into the search box.
Since search is substring matching and sorting is by recency, a
proj-prefix does nowork at all. Every project would carry it, so it distinguishes nothing, and you'd never
type it when looking for something.
Put the most sensitive thing in the name.
This one matters more than it looks. Keychain grants are bound to a scope through
audienceScopeId, and astandinggrant is injected into the environment on everylater turn — so every member of that project, on every turn, has that credential
available. Nothing leaks into a project on its own; someone has to grant it. But once
granted, it's ambient for everyone there.
So name it "Customer PII export", not "Data export". "Payroll", not "Finance misc". You
want the name to make you pause for a second before you paste something in.
The same logic says: don't open one big "Finance" project. Split by who should see what,
because the scope is the boundary for credentials and files, and the name is what reminds
you where that boundary is.
Add your own distinguishing word.
Since nothing checks for duplicates, "Audit" and "Audit" will sit there side by side. The
realistic collision isn't with a stranger's project — you can't see those — it's with one
you forgot you made, or one you were added to. Team, system, or year usually does it.
The shape I settled on
Some examples:
Finance monthly closePayrollInfra production accessFinance 2026 annual auditWarehouse migration 2026 Q3And what I stopped doing:
Misc/OtherInfra on-call runbookproj-paymentsPayments opsSprint 472026-08 closeFinance monthly closeEngineeringPayments on-call,Infra productionExportCustomer PII exportTwo things that are safe
The name is only visible to members. There's no org-wide project directory, so a specific
name won't show up in an unrelated colleague's list.
Renaming costs nothing — files, memory, and grants are untouched, and it doesn't even
bump
updatedAt. Start working, rename later if it turns out wrong.One caveat I hit: the only rename entry point I could find is the
⋯menu on a projectrow in the Chats sidebar, owner only. The Projects page, where you manage members, has no
rename control, which is why I first assumed projects couldn't be renamed at all. Filed
that separately as #321.
Minor mechanics
Names are trimmed, internal whitespace is collapsed to single spaces, and they're capped
at 200 characters. The sidebar is narrow, so short still wins.
All reactions