Persimmons 🍊
permissions, without the ceremony.
Passwords, PATs & plenty of other useful P's for humans + agents.
Persimmons is a small reusable-object layer over Gitea's existing user/repository Actions secrets + variables. Credentials are first; people / contacts remain a natural future Persimmon without being part of v0.
Live surface: https://🍵.teahub.xyz/🍊/
Product / secret naming
For new credential-backed Persimmons, the normalized Persimmon name is also the actual Gitea secret name and the card title.
MY_USEFUL_PASSWORD
→ Gitea secret: MY_USEFUL_PASSWORD
→ Persimmon title: MY_USEFUL_PASSWORD
Names normalize to Gitea-safe uppercase underscore form. Persimmons refuses to create over an existing secret with the same name.
Older objects created with PERSIM_SECRET_<id> remain fully supported; they are not silently renamed because their stored value is intentionally unreadable.
Identity boundary
The browser acts as the signed-in human:
🍊 page
→ teahub.xyz /tea/chat/persimmons/*
→ Tea verifies the Gitea web session
→ Tea uses that same signed-in Gitea session for Actions settings
→ caller Gitea permissions remain the effective boundary
Gitea's web session is not replayed as REST API authentication. Gitea 1.27 writes use same-origin request protection (Origin / Referer / same-origin fetch context), not the removed hidden _csrf token model.
MCP/agent reads use the MCP caller's OAuth identity. There is no service-account or hardcoded-user fallback.
Vault model
Persimmons
├── My vault
│ └── user Actions secrets + variables
└── Repository vaults
└── caller-authorized repository Actions secrets + variables
Existing Gitea secrets without Persimmons metadata are projected safely as legacy Persimmons using only Gitea-visible name, scope/context and availability. Provider/account/scopes are never fabricated.
Security boundary
human/browser provides a new value
→ selected Gitea protected store receives it
→ Persimmons exposes safe metadata + availability
→ stored value is never revealed back
No reveal/copy-after-storage endpoint exists.
Lifecycle: create → list → rotate → revoke → delete.
Contextual-use seam
Future tools should be able to ask Persimmons for authority in context:
domain()
→ Cloudflare connection required
→ choose/add Persimmon
→ bounded operation
→ domain() resumes
The generalized choose/use/resume framework, OAuth setup, people/contacts, and moving/sharing objects between vaults remain future work.