A CLI workspace is a folder on disk, usually your repository root, that holds a .xmatix/ settings folder and an xmatix/ tree with one file for each pulled artifact. Every CLI command works out which workspace it is in before it does anything else. Every pull writes into the xmatix/ tree, and every push, watch, snapshot import and migrate plan reads from it. The folder names are fixed in the CLI and can't be configured. You create a workspace with xmatix init, connect it to a tenant with xmatix login (Authentication), and then fill it with the pull commands.
.xmatix/
config.json # tenant, API and sign-in settings (no secrets)
.gitignore # ignores cache/ and tokens/ inside .xmatix/
.vscode/
tasks.json # two editor tasks written by init
xmatix/
metadata/
tenant-owned.json # metadata pull (name depends on --scope)
automation/
scripts/<Entity>/<Name>.csx # one script body per file
scripts/<Entity>/<Name>.meta.json # the script's id, version and bindings
rules/<Entity>/<Rule>.json # rule plus its actions
workflows/<Name>.json # full workflow definition
analytics/
dashboards/<Name>.json
reports/<Name>.json
packages/<packageId>/package.json # package manifest from package init
.snapshot/
migrate-plan.json # migrate plan output
server/ # kept by migrate plan --keep-server-snapshot
Overview
The workspace is the contract between the CLI and your repository. A command never asks which tenant or which folder to use. The tenant comes from .xmatix/config.json, and each artifact kind has one fixed folder. This keeps commands short and lets a whole team share one layout through git.
Sign-in tokens are never stored in the workspace. They are cached in your home folder under .xmatix/tokens/<tenant>/ and protected by the operating system (Authentication has the details). That home-folder cache has a side effect on workspace discovery, described under How xMatix handles it.
When to use it
- Read this page before you run
xmatix initin a repository, to decide where the workspace root should be. - Use it when a command acts on the wrong tenant or folder, or reports that no workspace was found.
- Use it when you decide what to commit and what to add to
.gitignore. - Use it when a pull leaves a second copy of an artifact, or a file you renamed doesn't rename anything on the server.
How xMatix handles it
Finding the workspace. The CLI starts in the current directory and walks up through each parent until it finds a directory that contains a .xmatix folder. That directory is the workspace root. No flag or environment variable overrides this. Where you run the command decides which workspace is used. If two workspaces are nested, the nearest one up the tree wins. If no directory up to the top of the drive contains .xmatix, the pull, push, list, watch, snapshot, migrate and package commands stop with "No xMatix workspace found. Run xmatix init in your repository root first."
Your home folder can count as a workspace. The token cache lives in a .xmatix folder in your home folder, and the CLI creates that folder the first time you sign in. From then on, your home folder passes the "contains .xmatix" test. A command run anywhere under your home folder, but outside a repository that has its own workspace, resolves to your home folder instead of saying that no workspace was found. Because there is normally no config.json there, the command stops with "Workspace exists but <home>/.xmatix/config.json is missing or unreadable. Run xmatix login to populate it." If you then run xmatix login there, the CLI writes its settings to your home folder, and every folder under home without its own workspace starts acting on that tenant. Always run xmatix init in the repository first, and check the root with xmatix doctor when in doubt.
What init creates. xmatix init uses the current directory as the root. It does not walk up. It creates:
.xmatix/config.jsonwith empty tenant, API, authority, client id and scope values, andapiVersionset tov1;.xmatix/.gitignore, which ignorescache/andtokens/inside.xmatix/;xmatix/automation/scripts/with an empty.gitkeep;.vscode/tasks.jsonwith two editor tasks: one pushes the script file that is open, and one pulls all scripts.
It writes each file only if it doesn't exist yet, so running init again never overwrites your settings. It creates no other xmatix/ folders. Each pull creates its folder the first time it writes.
What login changes. xmatix login writes the values you pass into the config.json of the workspace it finds. If it finds none, it creates .xmatix/config.json in the current directory.
Where each command reads and writes.
| Command | Folder | File names |
|---|---|---|
metadata pull | xmatix/metadata/ | tenant-owned.json by default. Other scopes write tenant-full.json, base-metadata.json, module-<packageId>.json, package-<packageId>.json or namespace-<namespace>.json. --out writes to any path instead. |
scripts pull | xmatix/automation/scripts/<Entity>/ | <Name>.csx plus <Name>.meta.json. The folder is the entity of the script's first binding that names an entity, or _unbound if none does. |
rules pull | xmatix/automation/rules/<Entity>/ | <Rule name>.json. Rules on an entity the CLI can't resolve go to _unknown/ (Business rules in the CLI). |
workflows pull | xmatix/automation/workflows/ | <Name>.json, or <definitionId>.json when the workflow has no name. |
dashboards pull, reports pull | xmatix/analytics/dashboards/, xmatix/analytics/reports/ | <Name>.json, or unnamed.json when the name is blank. In the current release these pulls write no files (Dashboards and reports). |
package init | xmatix/packages/<packageId>/ | package.json. package build writes <packageId>-<version>.artifact.json next to the manifest unless --out is given. |
migrate plan | xmatix/.snapshot/ | migrate-plan.json (or --out), and server/ when --keep-server-snapshot is set. |
snapshot import and migrate plan read every matching file in each artifact folder, including subfolders: *.json under metadata, rules, workflows, dashboards and reports, and *.csx under scripts. xmatix watch watches the scripts, rules, workflows, dashboards and reports folders, including subfolders, but not metadata.
File names. Files are named after the artifact's name, never its id, so listings and diffs read like the product. Any character that isn't allowed in a file name is replaced with _. Two different names can therefore produce the same file name, for example A/B and A:B both become A_B. When that happens the second artifact overwrites the first file during the pull.
Pulls never delete. No pull removes a file. When an artifact is renamed or deleted in the product, its old file stays in your workspace until you delete it.
What a push matches on. A push finds the server record from the file's contents, not from the file name or folder:
| Kind | Matched by | What a stale old file does when pushed |
|---|---|---|
| Script | The scriptId in the .meta.json | Pushes the old body as a new version of the same, renamed script. |
| Rule | The entityName and the rule name inside the file | Finds no rule with the old name, so it creates a second rule with the old name. |
| Workflow | The definitionId inside the file | Overwrites the renamed workflow with the old definition, including the old name. |
| Dashboard, report | The id inside the file | No effect in the current release, because these pushes fail. |
So renaming or moving a file on disk renames nothing on the server, and a stale file is never harmless: snapshot import pushes it along with everything else.
Prerequisites
- The xMatix CLI installed (The xMatix CLI).
- A repository, or another folder, that you want to be the workspace root.
- The tenant values for
xmatix login.
Procedure
Step 1 — Create the workspace in the repository root
Open a terminal in the repository root and run xmatix init. The CLI prints "Initialized xMatix workspace at <path>" and lists the files it created. Do this before you sign in from inside the repository, so that the repository, not your home folder, holds the settings.
Step 2 — Connect it to a tenant
From the same folder, run xmatix login with the tenant values (Authentication). The CLI prints the workspace root it saved the settings in. Check that it is the repository root and not your home folder.
Step 3 — Check the workspace
Run xmatix doctor. Its workspace line shows the resolved root, its config line shows the tenant and API URL, and each folder line shows whether a canonical folder exists. A missing folder is a warning ("missing — created on first pull"), not a failure. In the current release, doctor exits 1 even on a correct setup because of its api and scopes checks, so read the lines rather than the exit code.
Step 4 — Fill the tree
Run the pulls you need, for example xmatix metadata pull, xmatix scripts pull --all, xmatix rules pull and xmatix workflows pull, or xmatix snapshot export --skip scripts followed by xmatix scripts pull --all (Snapshots). Each pull prints the paths it wrote, relative to the workspace root.
Step 5 — Set up source control
Add xmatix/.snapshot/ to the repository's .gitignore, and also xmatix/automation/rules/_unknown/ if a rules pull created it. Then commit .xmatix/config.json, .xmatix/.gitignore and the xmatix/ tree. See What to commit.
Step 6 — Keep it in step with the product
After each pull, run git status. A new file next to an unchanged file with a similar name usually means the artifact was renamed in the product. Delete the old file in the same commit. When an artifact was deleted in the product, delete its file too, or the next snapshot import recreates or overwrites it.
What to commit
| Path | Commit? | Why |
|---|---|---|
.xmatix/config.json | Yes | It holds the tenant slug, URLs, client id, scopes and API version, and no secrets. Committing it gives the whole team the same setup. |
.xmatix/.gitignore | Yes | It keeps any cache/ and tokens/ folder inside .xmatix/ out of git. |
xmatix/metadata/, xmatix/automation/, xmatix/analytics/ | Yes | These are the artifacts you review and push. |
xmatix/packages/ | Yes, if you author packages | The manifest and the seed packs you build from. |
xmatix/.snapshot/ | No | Plan output and server copies are generated each time. init doesn't ignore this folder, so add it yourself. |
xmatix/automation/rules/_unknown/ | No | Rules the CLI couldn't place, which can't be pushed back. |
.vscode/tasks.json | Your choice | Editor convenience only. |
Tokens never reach the workspace, because they live in your home folder.
Example
A team keeps its tenant customisations in a repository called crm-config. A developer clones it to ~/work/crm-config. The repository already has a committed .xmatix/config.json, so they run xmatix login from inside ~/work/crm-config/xmatix/automation. The CLI walks up, finds ~/work/crm-config/.xmatix, and signs in to the configured tenant.
Later they open a terminal in ~/scratch, a folder with no workspace, and run xmatix rules list. Because they have signed in before, ~/.xmatix exists, and the CLI reports "Workspace exists but …/.xmatix/config.json is missing or unreadable." They realise they are in the wrong folder, cd back into the repository, and the command works.
A colleague renames the rule "Credit check" to "Credit limit check" in the product. The next xmatix rules pull writes Credit limit check.json and leaves Credit check.json. git status shows one new file and one unchanged file. The developer deletes Credit check.json in the same commit. If they had left it, the next snapshot import would have created a second rule called "Credit check".
Training
Practice exercise
In an empty folder inside a test repository, run xmatix init, then xmatix doctor. Expected result: the workspace line shows the folder, the config line shows an empty tenant, and five folder lines show "missing — created on first pull". The folder line for xmatix/automation/scripts is the only green one, because init created it. Then cd into xmatix/automation/scripts and run xmatix doctor again. Expected result: the same workspace root, because the CLI walks up to the nearest .xmatix.
Quick reference
- The workspace root is the nearest folder up the tree that contains
.xmatix. - After your first sign-in, your home folder also contains
.xmatix, so runinitin the repository first. initnever overwrites existing files and creates only the scripts folder.- Each artifact kind has one fixed folder; pulls create them as needed.
- Files are named after the artifact name, with invalid characters replaced by
_. - Pulls never delete files; delete stale files yourself.
- Pushes match on ids or names inside the file, not on the file name.
- Commit
.xmatix/config.jsonandxmatix/; ignorexmatix/.snapshot/andrules/_unknown/.
Permissions
The workspace itself needs only file-system access. Each command that talks to the tenant needs the permissions described on its own page.
Configuration
.xmatix/config.json is the only configuration file. xmatix login writes it, and you can also edit it by hand:
| Setting | What it means |
|---|---|
tenant | The tenant slug. It also names the token cache folder in your home folder. |
apiBaseUrl | The tenant's API base URL. This decides which organization every command acts on. |
authority | The sign-in authority URL. |
clientId | The client id of the CLI's sign-in registration. |
scopes | Space-separated scopes. When empty, the CLI asks for the API's default scope. |
apiVersion | The API version segment in each request. init sets v1. |
Authentication explains each value. Nothing else about the layout can be configured.
Common problems
"No xMatix workspace found. Run xmatix init in your repository root first."
No folder from the current directory up to the top of the drive contains .xmatix. Run the command from inside your repository, or run xmatix init in the repository root.
"Workspace exists but …/.xmatix/config.json is missing or unreadable"
The CLI found a .xmatix folder without a readable config.json. Most often this is your home folder's token cache, found because you ran the command outside any repository. cd into the repository. If the path really is your repository, run xmatix login there, or fix the JSON in config.json.
Commands act on the wrong tenant
You are inside a different workspace than you expect, or a config.json was written to your home folder. Run xmatix doctor and read the workspace line. If it shows your home folder, move into the repository. If you don't use your home folder as a workspace, remove config.json from ~/.xmatix/ but leave its tokens folder.
A pull created a second copy of an artifact
The artifact was renamed in the product, or two names became the same after invalid characters were replaced. Delete the stale file in the same commit as the pull.
A deleted or renamed artifact came back after snapshot import
A stale file was still in the workspace, and the import pushed it. For a rule that creates a new rule. For a script or workflow it overwrites the renamed one. Delete the stale file, then fix the server record in the product or push the current file again.
xmatix watch says "Nothing to watch"
None of the watched folders exists yet, or you turned every group off. Pull at least one artifact kind first.
Common questions
Can I move artifacts to different folders?
No. The folder names are built into every command, and push, watch, snapshot import and migrate plan only look in those folders. You can choose where the workspace root lives and which artifact kinds you use. Unused folders just stay empty or are never created. The one exception is metadata pull --out, which can write the seed pack to any path. snapshot import and migrate plan only see files under xmatix/metadata/.
Does one repository support several tenants?
One workspace serves one tenant, but a repository can hold several workspaces in separate folders, each with its own .xmatix/ and xmatix/ tree. Commands act on whichever workspace contains your current directory, so switching tenants means changing directory. Each workspace's tokens are cached by tenant slug, so two workspaces with different slugs keep separate sign-ins. Two workspaces with the same slug share one token cache.
Why does doctor warn about missing folders?
init creates only the scripts folder. The others appear the first time the matching pull writes a file. A missing folder is reported as a warning and does not count as a failure.
Is .vscode/tasks.json required?
No. It is a convenience: one task pushes the script that is open in the editor, and another pulls all scripts. Delete it or change it as you like. init won't recreate it unless the file is missing.
