Skip to content

Commit d8f71fe

Browse files
feat(skills): add portable imports and workspace sync guidance
2 parents 8e852da + 9a6826d commit d8f71fe

8 files changed

Lines changed: 212 additions & 25 deletions

File tree

.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "sim",
33
"displayName": "Sim",
44
"version": "0.1.0",
5-
"description": "Build, run, deploy, and operate Sim workflows, tables, and knowledge bases.",
5+
"description": "Build, run, deploy, and sync Sim workflows; operate tables and knowledge bases.",
66
"author": {
77
"name": "Sim",
88
"url": "https://sim.ai"

.codex-plugin/plugin.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "sim",
33
"version": "0.1.0",
4-
"description": "Build, run, deploy, and operate Sim workflows, tables, and knowledge bases.",
4+
"description": "Build, run, deploy, and sync Sim workflows; operate tables and knowledge bases.",
55
"author": {
66
"name": "Sim",
77
"url": "https://sim.ai"
@@ -14,7 +14,7 @@
1414
"interface": {
1515
"displayName": "Sim",
1616
"shortDescription": "Build and operate Sim workflows",
17-
"longDescription": "Use the Sim CLI to build, test, deploy, and debug workflows, plus manage tables and knowledge bases.",
17+
"longDescription": "Use the Sim CLI to build, test, deploy, and debug workflows, import and sync workspaces, and manage tables and knowledge bases.",
1818
"developerName": "Sim",
1919
"category": "Productivity",
2020
"capabilities": ["Read", "Write"],

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,4 @@ jobs:
4848
test -f "$PACKAGE_DIR/package/.codex-plugin/plugin.json"
4949
test -f "$PACKAGE_DIR/package/.claude-plugin/plugin.json"
5050
test -f "$PACKAGE_DIR/package/skills/build-workflow/SKILL.md"
51+
test -f "$PACKAGE_DIR/package/skills/sync-workspaces/SKILL.md"

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ Native plugin installs expose the skills under the `sim` namespace:
7373
- `sim:build-workflow`
7474
- `sim:run-workflow`
7575
- `sim:deploy-workflow`
76+
- `sim:sync-workspaces`
7677
- `sim:table`
7778
- `sim:knowledge-base`
7879

@@ -83,7 +84,11 @@ Direct installs through `bunx sim-skills` install the selected skills without th
8384
- `build-workflow` — discover blocks and author a draft graph with atomic workflow operations.
8485
- `run-workflow` — test saved state, exercise triggers, resume from a block, and diagnose runs.
8586
- `deploy-workflow` — publish and manage workflows as APIs, chats, or MCP tools.
87+
- `sync-workspaces` — import portable workflows with bindings, fork workspaces, and preview, apply, and reconcile push/pull sync.
8688
- `table` — design typed tables, load and query rows, import data, and run workflow groups.
8789
- `knowledge-base` — ingest and index documents, configure connectors and tags, and verify retrieval.
8890

8991
The skills assume the `sim` CLI is installed and authenticated. They never store or print API keys.
92+
93+
Workspace sync guidance requires a CLI and server exposing the v2 import-preview and fork sync
94+
commands. The skill checks command availability before changing resources.

scripts/validate-skills.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const expectedSkillNames = [
1616
"knowledge-base",
1717
"run-tool",
1818
"run-workflow",
19+
"sync-workspaces",
1920
"table",
2021
] as const;
2122
const expectedPackageFiles = [

skills/build-workflow/SKILL.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ A request that is one action against one connected service needs no graph at all
1212
directly with `sim tools execute` (see the `run-tool` skill). Build a workflow when the task needs
1313
more than one call, branching, or a schedule.
1414

15+
For an existing workflow JSON import or environment promotion, use the `sync-workspaces` skill.
16+
It preserves registered reference identities through preview and destination binding before graph IDs
17+
are regenerated; do not recreate that flow with a sequence of graph edits.
18+
1519
## Establish context
1620

1721
- Use the profile the user named. If none was named, inspect configured profiles and current context;

skills/deploy-workflow/SKILL.md

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -56,28 +56,22 @@ Do not choose a surface from convenience. Ask when the intended caller does not
5656

5757
## Promoting across workspaces with fork sync
5858

59-
When a workflow moves between workspaces via a fork push, the sync has its own semantics; do not
60-
reason about it as a copy.
61-
62-
- The push creates resources that are missing in the target and rebinds selector-bound references
63-
to them. Do not pre-create tables in the target as a promotion prerequisite - pre-creating
64-
defeats the mapping and leaves references pointing at the source.
65-
- A table the push creates arrives holding the source's rows. Re-seed environment-specific values,
66-
feature flags and configuration especially, immediately after the push, before anything reads
67-
them. Where possible design flag rows so the source's value is also the safe value in every
68-
target.
69-
- Deployment state travels. A workflow deployed in the source is live in the target as soon as the
70-
sync completes, and a schedule trigger starts firing there on its own - there is no separate
71-
deploy step in the target. Before syncing anything scheduled or triggered, state plainly what
72-
will start running where and when.
73-
- Bind every resource through its selector and leave the manual id fields empty. The push remaps
74-
selectors but carries a hardcoded manual id verbatim, silently pointing the promoted workflow at
75-
the source workspace's resource - and a cross-workspace read succeeds, so no error surfaces.
76-
- The push does not preserve a block's basic/advanced mode: some blocks arrive rebound and working,
77-
others arrive carrying the source's manual id and broken, with nothing surfacing which is which.
78-
"Works in the source workspace" is therefore never the completion condition. Verify each target
79-
environment after promotion - run its workflows or audit its bindings - rather than inferring
80-
health from the source.
59+
Use the `sync-workspaces` skill for portable imports, workspace forks, and push/pull promotion.
60+
That flow owns mapping discovery, preview fingerprints, stable request IDs, and operation polling.
61+
62+
- Sync transfers deployed source versions along a direct fork edge. Push sends current → other;
63+
pull receives other → current, regardless of which workspace is the child.
64+
- Select resource copies explicitly or map to existing authorized destination resources. Creating a
65+
destination table is valid when mapping to it; sync does not automatically copy every missing
66+
resource. Selected table copies include rows, so review environment-specific configuration.
67+
- Import and fork create drafts. Sync deploys eligible admitted snapshots after background work;
68+
inspect operation and deployment readiness before declaring the target live. Schedules and
69+
webhooks can begin receiving traffic when their deployment activates.
70+
- Registered selector references are remapped using canonical field modes. Manual values remain
71+
literal; verify their intended destination instead of assuming they were rebound or that access
72+
across workspaces is permitted.
73+
- Review trigger URL changes and required configuration. A committed operation can still need
74+
configuration or have failed follow-up work; an HTTP success alone does not establish readiness.
8175

8276
## Verify and report
8377

skills/sync-workspaces/SKILL.md

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
---
2+
name: sync-workspaces
3+
description: Import portable Sim workflow JSON with destination bindings, create workspace forks, or push and pull deployed workflows along a fork edge through the sim CLI. Use for environment promotion, mapping and selector discovery, preview/apply retries, and operation readiness; not for authoring a new graph or ordinary deployment.
4+
---
5+
6+
# Import and Sync Sim Workflows
7+
8+
Use a reviewed preview, explicit destination bindings, and a durable request ID. Verify the returned
9+
operation; sync also requires target deployment readiness. Imports and forks complete as drafts.
10+
11+
## Establish scope
12+
13+
- Use the user's profile, API origin, and explicit workspace. Inspect context before selecting an
14+
environment; never silently change accounts. Do not print or store authentication secrets.
15+
- Check `sim workflows import-preview --help` or `sim workspaces push-preview --help` first. These
16+
commands require a CLI and server with the v2 sync feature. If unavailable, report the missing
17+
capability and required upgrade; do not substitute private browser endpoints.
18+
- Fork creation requires source admin. Sync and mapping changes require admin on both workspaces.
19+
Fork administration accepts personal API keys or OAuth, not workspace keys. Imports retain their
20+
existing workflow-write permissions; credential binding still requires an eligible acting user.
21+
- Inspect `workspaces fork-availability` before forking. Enterprise/self-hosting and workspace
22+
creation policies still apply. OAuth scopes and permission groups can further restrict access.
23+
- Use `--output json`. Single-resource CLI results are unwrapped objects; paged results contain
24+
`data` and `nextCursor`. Raw v2 HTTP single-resource responses wrap the object in `data`.
25+
26+
## Choose the operation
27+
28+
| Intent | Commands | Result |
29+
| --- | --- | --- |
30+
| Import workflow JSON into an authorized destination | `workflows export`, `import-preview`, `import` | New undeployed draft with regenerated graph IDs |
31+
| Create a child environment | `workspaces fork-preview`, `fork` | Child workspace with eligible deployed source workflows copied as drafts |
32+
| Send current workspace changes to its direct fork neighbor | `workspaces push-preview`, `push` | Replace eligible target workflows from deployed source versions |
33+
| Receive changes from a direct fork neighbor | `workspaces pull-preview`, `pull` | Same sync with the other workspace as source |
34+
35+
Push always means current → other; pull means other → current, on either side of the parent/child
36+
edge. Inspect `workspaces lineage` and `children`; do not infer direction from the word child.
37+
Arbitrary workspace transfers and draft sync are outside this flow.
38+
39+
## Portable import
40+
41+
Export with reference metadata and preview in the destination:
42+
43+
```sh
44+
sim --profile source --workspace "$SOURCE_WORKSPACE" --output json \
45+
workflows export "$WORKFLOW_ID" --include-references > workflow.json
46+
sim --profile destination --workspace "$DESTINATION_WORKSPACE" --output json \
47+
workflows import-preview --workflow @workflow.json > preview.json
48+
```
49+
50+
Default export remains sanitized without reference metadata. `--include-references` records
51+
registered non-secret source IDs and every block/field occurrence alongside the sanitized graph.
52+
Treat imported IDs and provenance as untrusted labels, not authorization to read a source workspace.
53+
54+
Read `unresolvedBindings`, `unresolvedConfiguration`, and target-discovery instructions. Discover
55+
destination credentials, tables, files, sandboxes, and other resources through their existing CLI
56+
commands. Candidate matches are suggestions; verify provider, resource type, and parent resource.
57+
Missing OAuth connections can require human provider authorization; report that requirement rather
58+
than inventing a connection or substituting a different user's credential.
59+
60+
Import resource mappings use `kind`, `sourceId`, and `targetId`:
61+
62+
```json
63+
[
64+
{ "kind": "credential", "sourceId": "source-connection", "targetId": "destination-connection" },
65+
{ "kind": "sandbox", "sourceId": "source-sandbox", "targetId": "destination-sandbox" }
66+
]
67+
```
68+
69+
For older exports, `--bindings` addresses a specific registered source occurrence. For example:
70+
71+
```json
72+
[
73+
{ "kind": "sandbox", "blockId": "source-function", "subBlockKey": "sandboxId", "targetId": "destination-sandbox" }
74+
]
75+
```
76+
77+
`valuePath` defaults to `[]` and `encoding` to `scalar`. Use preview/manifest occurrence paths for
78+
nested or multi-value fields; do not guess them. Conflicting mappings and bindings are rejected.
79+
Import dependent values use `{blockId, subBlockKey, value}`, such as
80+
`{"blockId":"source-agent","subBlockKey":"tools[0].folder","value":"destination-label"}`.
81+
Keep the original source IDs and tool indexes until apply returns `idMap`.
82+
83+
Save the exact input files and a client-generated stable request ID before applying:
84+
85+
```sh
86+
sim --profile destination --workspace "$DESTINATION_WORKSPACE" --output json \
87+
workflows import-preview --workflow @workflow.json \
88+
--mappings @mappings.json --dependent-values @values.json > preview.json
89+
sim --profile destination --workspace "$DESTINATION_WORKSPACE" --output json \
90+
workflows import --workflow @workflow.json \
91+
--mappings @mappings.json --dependent-values @values.json \
92+
--preview-fingerprint "$(jq -r .previewFingerprint preview.json)" \
93+
--request-id "$REQUEST_ID" --wait
94+
```
95+
96+
Include the same name, folder, bindings, and other choices on both requests. JSON flags accept
97+
`@file` and `@-` for stdin; only one input can consume stdin. Mapped import creates nothing while
98+
required bindings remain unresolved. It commits the draft, graph, variables, inline custom tools,
99+
and receipt together. Mappings are local to this request; importing does not create a workflow
100+
correspondence on a fork edge. Plain imports without mapping options
101+
retain legacy behavior; use preview/apply for automation that needs binding guarantees.
102+
103+
## Fork and sync choices
104+
105+
Inspect `workspaces fork-resources`, then preview with explicit copy selections. A fork's
106+
`--copy` selects source resources; sync uses `--copy-resources`. Consult command help for each
107+
shape: fork file selections are workspace file IDs, while sync file selections are storage keys.
108+
Copying is opt-in. Selected table copies include rows and selected knowledge bases include content;
109+
account for environment-specific configuration before enabling the destination.
110+
111+
Existing destination resources can be mapped instead of copied. Sync mapping entries use
112+
`{resourceType, sourceId, targetId}`; they differ from import's `kind` entries. In particular,
113+
portable `credential` corresponds to sync `oauth_credential` or `service_account_credential`.
114+
Verify the actual credential type through resource discovery. A mapping inspection row also has
115+
`id`; project it before reuse with `jq '.data | map({resourceType,sourceId,targetId})'`. Follow all
116+
pages first. Newly referenced resources may have no persisted mapping row yet.
117+
118+
Previews evaluate inline mappings without saving them. Accepted inline sync mappings persist on
119+
the canonical edge in the same transaction as sync; a refusal before commit saves neither.
120+
Dependent sync values use `{sourceWorkflowId, sourceBlockId, subBlockKey, value}`. Never use fresh
121+
target IDs from preview as override identities. Omitted overrides reuse saved sync choices; values
122+
that exist only in a target draft are not saved choices. A supplied `dependentValues` array replaces
123+
the saved choices for affected workflows; `[]` clears them. Start from every preview configuration
124+
field and its `currentValue`, edit the intended selections, and submit the complete set of choices
125+
to retain, rather than only the changed fields.
126+
127+
For every dependent field, use its returned selector key, context, and `discoveryWorkspaceId`:
128+
129+
```sh
130+
sim --profile destination --workspace "$DISCOVERY_WORKSPACE" --output json \
131+
selectors list --selector-key gmail.labels \
132+
--context '{"oauthCredential":"destination-connection"}'
133+
```
134+
135+
The discovery workspace is the source when the parent resource will be copied, and the destination
136+
when using an existing mapping. Use a profile authorized for that workspace. Follow `nextCursor`,
137+
inspect truncation metadata, and use `selectors get --help` to verify a particular option. A clipped
138+
list does not prove an option is absent. Resolve dependent chains in order, re-previewing with the
139+
new choices. Use exactly the returned context for MCP tool discovery as well.
140+
141+
```sh
142+
sim --profile destination --workspace "$DESTINATION_WORKSPACE" --output json \
143+
workspaces pull-preview --other-workspace-id "$SOURCE_WORKSPACE" \
144+
--mappings @sync-mappings.json --dependent-values @sync-values.json > sync-preview.json
145+
sim --profile destination --workspace "$DESTINATION_WORKSPACE" --output json \
146+
workspaces pull --other-workspace-id "$SOURCE_WORKSPACE" \
147+
--mappings @sync-mappings.json --dependent-values @sync-values.json \
148+
--preview-fingerprint "$(jq -r .previewFingerprint sync-preview.json)" \
149+
--request-id "$SYNC_REQUEST_ID" --yes --wait
150+
```
151+
152+
Use `--yes` within the user's authorized destructive sync scope. Review replacements, exclusions,
153+
resource selections, required configuration, and trigger URL changes before apply. If preview offers
154+
trigger adoption choices, use its stable source workflow/block identities and offered paths; never
155+
invent a path. Sync `ready` indicates commit readiness, not a live deployment. Scheduled or webhook
156+
workflows can begin receiving traffic once admitted deployments activate.
157+
158+
## Completion and recovery
159+
160+
- Save `operationId`, `requestId`, and the receipt's `workspaceId`. Import receipts belong to the
161+
destination; fork and push/pull receipts belong to the workspace on which the command was invoked.
162+
Poll that scope even when the created child or sync target is a different workspace.
163+
- `applied: true` means the transaction committed, including when later copy/deployment work fails.
164+
Use `workspaces operations get <operationId>` or `wait <operationId> --wait-timeout 300` to refresh
165+
readiness. Operation lists are stored snapshots; filter with `--request-id` to recover a lost ID.
166+
- Require terminal readiness and inspect issues/trigger URL changes before declaring the environment
167+
ready. Completed-with-warnings exits 0 but still needs review. Required configuration exits 3,
168+
failed completion exits 1, and wait timeout exits 4. Timeout diagnostics retain reconciliation IDs.
169+
- After an uncertain response, retry identical inputs with the original request ID, or poll the
170+
existing operation. Never retry an uncertain mutation with a fresh ID. Same ID with changed input
171+
returns 409. Authorize access again before reconciliation; a stored receipt is not an auth bypass.
172+
- A stale preview with no committed operation needs a fresh preview and a new request ID for the
173+
revised inputs. Resolve structured 409 issues; do not loop blindly or remove safety flags.
174+
- Sync transfers deployed source versions. Merely undeploying a source does not archive its target;
175+
deleting a mapped source can. Respect explicit sync exclusions.
176+
- Rollback restores the latest target sync from prior deployed versions. It does not recover
177+
arbitrary prior drafts or remove every copied resource. Use rollback/unlink/exclusion controls
178+
only for the requested recovery scope and verify their result.
179+
180+
For a new imported draft, use the `run-workflow` skill to test it and `deploy-workflow` only when
181+
publication is requested. Never copy secret values, signed URLs, arbitrary headers, or opaque
182+
credential payloads between environments to make a binding pass.

0 commit comments

Comments
 (0)