Tool Accounts¶
Tools are bot or service accounts that authenticate with the server just like users, but without the ability to have roles — every permission must be explicitly granted. Use them for:
- Automated posting bots (alerts, notifications, CI/CD updates)
- Background workers that read or process messages
- Third-party integrations
- Webhook receivers
Creating a tool account¶
Step 1 — Generate a keypair for the tool¶
Each tool has its own Ed25519 keypair. Generate one and save both keys:
import os
from reeeductio.crypto import generate_keypair, to_tool_id
private_key, public_key = generate_keypair()
tool_id = to_tool_id(public_key) # starts with 'T'
print('Tool ID: ', tool_id)
print('Private key: ', private_key.hex())
print('Public key: ', public_key.hex())
# Store both keys — you need the public key to reconstruct the tool ID later
import { generateKeyPair, toToolId } from 'reeeductio';
const keyPair = await generateKeyPair();
const toolId = toToolId(keyPair.publicKey); // starts with 'T'
console.log('Tool ID: ', toolId);
console.log('Private key: ', Buffer.from(keyPair.privateKey).toString('hex'));
console.log('Public key: ', Buffer.from(keyPair.publicKey).toString('hex'));
Step 2 — Register the tool in the space (as admin)¶
Step 3 — Grant capabilities to the tool¶
Tools have no permissions by default. Grant exactly what they need:
# Allow the tool to post to the alerts topic
space.grant_capability_to_tool(
tool_id='T...',
cap_id='post-alerts',
capability={'op': 'create', 'path': 'topics/alerts/messages/{any}'},
)
# Allow the tool to read all topics (e.g. for a read-only bot)
space.grant_capability_to_tool(
tool_id='T...',
cap_id='read-all',
capability={'op': 'read', 'path': 'topics/{any}'},
)
Using a tool account in code¶
Tools authenticate and make API calls exactly like users. Pass the tool's private key, its public key, and the symmetric_root to your bot process:
import os
from reeeductio import Space
from reeeductio.crypto import to_tool_id
# Load credentials from environment
tool_private_key = bytes.fromhex(os.environ['TOOL_PRIVATE_KEY'])
tool_public_key = bytes.fromhex(os.environ['TOOL_PUBLIC_KEY'])
symmetric_root = bytes.fromhex(os.environ['SYMMETRIC_ROOT'])
space_id = os.environ['SPACE_ID']
tool_id = to_tool_id(tool_public_key)
space = Space(
space_id=space_id,
member_id=tool_id,
private_key=tool_private_key,
symmetric_root=symmetric_root,
base_url='https://your-server.example.com',
)
# Post an alert
space.post_encrypted_message('alerts', 'alert.info', b'Build succeeded!')
import { Space, toToolId, stringToBytes } from 'reeeductio';
const privateKey = Uint8Array.from(Buffer.from(process.env.TOOL_PRIVATE_KEY!, 'hex'));
const publicKey = Uint8Array.from(Buffer.from(process.env.TOOL_PUBLIC_KEY!, 'hex'));
const symmetricRoot = Uint8Array.from(Buffer.from(process.env.SYMMETRIC_ROOT!, 'hex'));
const spaceId = process.env.SPACE_ID!;
const keyPair = { privateKey, publicKey };
const toolId = toToolId(publicKey);
const space = new Space({ spaceId, keyPair, symmetricRoot, baseUrl: 'https://your-server.example.com' });
await space.postEncryptedMessage('alerts', 'alert.info', stringToBytes('Build succeeded!'));
Storing tool credentials safely¶
Never hardcode credentials. Use your platform's secrets manager:
| Platform | Recommended approach |
|---|---|
| Docker / Compose | secrets: block or .env file |
| Kubernetes | Secret objects, mounted as env vars |
| GitHub Actions | Encrypted Actions secrets |
| AWS | Secrets Manager or Parameter Store |
| Cloud Run | Secret Manager |
The bot needs four values: TOOL_PRIVATE_KEY, TOOL_PUBLIC_KEY, SYMMETRIC_ROOT, SPACE_ID.
Removing a tool¶
After removal, the tool's authentication attempts will be rejected by the server.
Example: CI/CD notification bot (GitHub Actions)¶
- name: Notify rEEEductio
env:
TOOL_PRIVATE_KEY: ${{ secrets.REEEDUCTIO_TOOL_PRIVATE_KEY }}
TOOL_PUBLIC_KEY: ${{ secrets.REEEDUCTIO_TOOL_PUBLIC_KEY }}
SYMMETRIC_ROOT: ${{ secrets.REEEDUCTIO_SYMMETRIC_ROOT }}
SPACE_ID: ${{ secrets.REEEDUCTIO_SPACE_ID }}
run: |
pip install reeeductio
python - <<'EOF'
import os
from reeeductio import Space
from reeeductio.crypto import to_tool_id
tool_id = to_tool_id(bytes.fromhex(os.environ['TOOL_PUBLIC_KEY']))
space = Space(
space_id=os.environ['SPACE_ID'],
member_id=tool_id,
private_key=bytes.fromhex(os.environ['TOOL_PRIVATE_KEY']),
symmetric_root=bytes.fromhex(os.environ['SYMMETRIC_ROOT']),
base_url='https://your-server.example.com',
)
space.post_encrypted_message('alerts', 'ci.deploy', b'Deployed to production!')
EOF
Related¶
- Add Users — adding human members
- Manage Permissions — roles and capabilities in depth
- Access Control — concept overview