Workspace Sync & Share
TF Code integrates deeply with your ToothFairyAI workspace. Two commands move agents and skills between the two sides:
tfcode sync— the pull (downstream). Downloads your workspace's coder agents, agent skills, functions, and prompts into a local cache so Build and other agents can use them. It also pulls workspace policies and the workspace-managed tfcode.json when present.tfcode agent share— the push (upstream). Uploads a local agent (and the skills it references) to your workspace as acoderagent.
They are exact mirrors of each other: sync pulls, share pushes.
Setup
Both commands use the active profile's credentials.
# Configure credentials (creates a profile)
tfcode setup
# Validate
tfcode validate
# Switch profile if you have more than one workspace
tfcode profile prod
Pass --profile <name> (or -p <name>) to either command to target a specific profile without switching:
tfcode sync --profile prod
tfcode agent share foo --profile prod
Sync (pull / downstream)
tfcode sync
tfcode sync --force # force a full re-sync
tfcode tools list # list what was synced
Sync calls your workspace API to read:
/agent/list→ coder agents and retriever agents (withagenticRAGoruseInterleavedReasoningenabled)/hook/list→ execution hooks/function/list→ agent_skill / api_function tools/prompt/list→ prompts
and caches the result to disk (.tfcode/tools.json, or .tfcode/tools-<profile>.json for non-default profiles).
The synced coder agents and agent skills then appear at runtime as read-only agents and skills (tagged [TF-synced] in the /agents dialog and the agent tool). They are merged with your local agents — a local agent with the same name takes precedence.
| Source | Editable? |
|---|---|
Local .tfcode/agent/*.md | Yes (agent tool, agent create/update/delete) |
| TF-synced (from sync) | Read-only (cannot be edited or deleted locally) |
Retriever agent sync
Retriever agents (mode: "retriever" with agenticRAG or useInterleavedReasoning enabled) sync as recomposed-markdown agents: instead of separate cloud fields, ALL their behavioural instructions are recomposed into one markdown document — the agent's local system prompt:
| Cloud field | Markdown section |
|---|---|
interpolationString (role and instructions) | Role and instructions |
goals | Goals |
customToolingInstructions (tooling guidelines) | Tooling guidelines |
ragInstructions (agentic search) | Agentic search instructions |
planningInstructions | Planning instructions |
reviewInstructions | Review instructions |
inhibitionPassage / pertinencePassage | Guardrails |
defaultAnswer / noKnowledgeDefaultAnswer | Fallback answers |
agentFunctions (ids) | Tools (resolved to synced tf.tools.<name> names) |
customCodeExecutionEnvironments (ids) | Execution hooks (with hook ids) |
agentFnParams | Tool parameters (JSON) |
functionContext | Tool context (JSON) |
Retriever agents run both ways:
- Locally — the recomposed markdown drives the local model; assigned workspace tools are called with
tf.tools.*, hooks execute server-side withtf_hook_execute(secrets stay cloud-side). - Cloud delegation — the frontmatter carries
tf_agent_id, sotf_cloud_agent(and TF Orchestrate's roster) can delegate to the cloud version where the full agenticRAG / knowledge-hub flow executes.
Each synced retriever agent is also written as a real local agent file at .tfcode/agent/<name>.md (previous version kept as .bak) so you can inspect and extend it between syncs — sync regenerates it on every run.
agentFnParams semantics match the backend: when a synced TF agent is the active agent, its parameters are merged into the body of every tf.tools.* call and override the tool's own parameters.
Workspace-managed config & policies
After the tool sync, tfcode sync also pulls two extra artifacts when the workspace admin has published them (stored as workspace documents under the tfcode context, fetched through the same presigned-download flow used elsewhere in ToothFairyAI):
- Policies → cached to
~/.tfcode/policy[-<profile>].jsonand enforced at runtime. See Policies. - tfcode.json → replaces your global config file (
~/.config/tfcode/tfcode.json) so admins can centrally ship models, permissions, agents, and more.
The config replace is guarded:
- The downloaded JSON is validated against the TF Code config schema before anything is written.
- The previous global config is kept as
tfcode.json.bak. - On validation failure the sync aborts the replace with a clear error and your current config stays in effect.
Project-level tfcode.json files are never touched.
Share (push / upstream)
Upload a local agent to your workspace as a coder agent.
# Create (or update) the agent "frontend-coder" + its referenced skills
tfcode agent share frontend-coder
# Target a specific profile
tfcode agent share frontend-coder --profile prod
# Preview what would be uploaded without making changes
tfcode agent share frontend-coder --dry-run
# Force-update a same-name workspace agent that has no local tf_agent_id
tfcode agent share frontend-coder --force
What gets uploaded
The command reads the local agent's markdown file from .tfcode/agent/<name>.md or .tfcode/agents/<name>.md and maps the fields:
| Local field | Cloud field | Notes |
|---|---|---|
name | label | |
description | description | |
| body (system prompt) | interpolationString | The "instructions" field |
goals | goals | |
temperature | temperature | |
model | llmBaseModel + llmProvider | Only sent when the provider is toothfairyai / tf |
Referenced skills are uploaded first (as agent_skill functions) and then linked to the agent. TF Code discovers the skills a local agent uses through its permission.skill.* allow rules:
---
permission:
skill:
"frontend-review": allow
---
You are a senior frontend engineer. ...
Each uploaded skill is recorded in a sidecar tf.json next to its SKILL.md, so a later share updates the same skill instead of creating a duplicate.
What is NOT uploaded
TF Code deliberately does not manage the many cloud-only agent fields. All of the following are left at their workspace defaults (never sent): every custom*Instructions field (customGreetingInstructions, customConclusionInstructions, customChartingInstructions, customSummarisationInstructions, customImagesInstructions, customToolingInstructions), plus planningInstructions, reviewInstructions, ragInstructions, voiceInstructions, analyticsInstructions, virtualDesktopInstructions, dynamicModelSelectionInstructions, and every planner / RAG / voice / memory / images / moderation field. Local agents only own the fields in the table above, and we keep it that way.
Create vs update (identity tracking)
agent share decides whether to create or update like this:
- If the local file has a
tf_agent_idfrontmatter, it updates that exact cloud record. This is the round-trip path — pull, edit, push a new version to the same agent your teammates already use. - Otherwise it looks for a workspace coder agent with
label === name:- found → warns and aborts unless
--force(which updates it); - not found → creates a new agent.
- found → warns and aborts unless
- On create, the resulting cloud id is stamped back into the local
tf_agent_idfrontmatter, so future shares keep updating the same record.
After a successful share, agent share re-runs sync so your local cache matches the cloud again.
The full round-trip
workspace (cloud) local disk workspace (cloud)
───────────────────── ────────────── ─────────────────────
coder agent A ─ sync ──▶ tools.json
(read-only, [TF-synced])
│ pull into a local .md
▼
.tfcode/agent/copy-of-a.md
(frontmatter tf_agent_id = A.id)
│ edit prompt / skills
▼
tfcode agent share copy-of-a
── POST /agent/update id=A ──▶ coder agent A (new version)
+ re-sync ◀───────────────────────────┘
Because tf_agent_id is preserved on the local file, sharing an edited copy updates the original cloud agent — teammates pick up the new version without a naming conflict.
Troubleshooting
| Error | Fix |
|---|---|
No profile configured | Run tfcode setup first. |
Local agent "<name>" not found | Create it (tfcode agent create) or add .tfcode/agent/<name>.md. |
already exists ... no local tf_agent_id | The name is taken in the workspace but the local file has no cloud id. Re-run with --force to update, or rename. |
model not uploaded | Only toothfairyai / tf provider models are sent; other providers are left to the workspace default. |