How an agent (or a person at a shell) changes an IDM driver set without Designer: the tree is the source of truth, the CLI keeps it consistent, the validator is the engine's own verdict, and git is the history.
A human learning the product starts at the repository README and docs/README.md (getting-started.md, day-to-day.md, tree-layout.md). This page is the same loop with the refusal rules spelled out. How to give it to Claude Code, Cursor, or another agent is agents.md.
bin/idm with no arguments prints every command with its arguments. Where
this page and that text disagree, follow bin/idm. Edit operations are
command <tree> --flag value (for example --form, --prd, --props).
--json always means machine-readable output.
An IDM-as-code tree (model.md) — one file per object:
tree/
driverset.xml manifest: drivers, driver-set linkage, meta
config-values.xml driver-set GCVs
library/library.xml Library manifest
library/<name>.policy.xml shared policies, mapping tables, GCV objects, ECMAScript
drivers/<driver>/driver.xml manifest: config files, icon, artifacts, policy-set linkage
drivers/<driver>/icon.gif the driver's Designer icon, if it has one (opaque bytes)
drivers/<driver>/*.policy.xml driver-scope policies (schema map, input/output transforms, …)
drivers/<driver>/subscriber/… channel policies
drivers/<driver>/publisher/…
.package-baseline/… pre-edit content of customized packaged artifacts
Forms, PRDs, entitlements, and the rest of AppConfig live under the driver as
well. The plain-language map, including cases/ and the secrets files beside
the tree, is tree-layout.md.
Artifacts are addressed by path: library/<name>, drivers/<driver>/<name>,
drivers/<driver>/subscriber/<name>, drivers/<driver>/publisher/<name>.
Names are the object names (spaces and all); quote them.
Get a tree from any source:
bin/idm import <driver-or-driverset-export.xml> tree/
bin/idm import-project <designer-project-dir> tree/
bin/idm import-ldif <driverset-subtree.ldif> tree/ # a subtree export from the driver set's DN, objectClass included
bin/idm import-live tree/ --env stg # connection + driver set from environments.properties (preferred)
IDM_JAVA_OPTS="-Dldap.url=ldaps://host:636 -Dldap.bindDn=… -Dldap.password=…" \
bin/idm import-live "cn=driverset1,o=system" tree/Put it in git before editing. The import is byte-idempotent, so re-importing
the same source is a no-op diff — which is how you see what changed in a vault.
The import writes a .gitattributes (* -text) so git never normalizes line
endings: vault content is bytes, and a CRLF inside an ECMAScript resource must
survive a checkout or vault.diff will report it. Keep that file.
bin/idm validate tree/ # the baseline: is this tree sound?
bin/idm query tree/ artifacts "AD Driver" # what the driver has
bin/idm query tree/ chain "AD Driver" sub # the subscriber chain in execution order
bin/idm query tree/ gcvs "AD Driver" # every GCV in scope, value, and where it's defined
bin/idm query tree/ tables "AD Driver" # mapping tables in reach, with columns
bin/idm show tree/ "drivers/AD Driver/subscriber/sub-ctp-Transform"
bin/idm refs tree/ "library/lib-Shared" # who links / includes / maps it
bin/idm query tree/ drivers # driver names and directories
bin/idm query tree/ fishbone "AD Driver" # the policy-flow fishbone (--json for the VS Code viewer)validate on a tree from a running vault should report 0 errors. If it
doesn't, the errors are real (a dangling reference, a GCV nothing defines) — or
a validator bug, which is the same as a finding: report it, don't work around it.
A User Application driver's cn=AppConfig subtree (JSON/Form.io provisioning
forms and their request definitions — see forms.md) reads and
writes with import/import-project/import-ldif/import-live like any
other driver content, under drivers/<driver>/provisioning/.
bin/idm form.list tree/ --driver "User Application Driver" # kind, name, title, #fields, packaged mark
bin/idm form.show tree/ "Help-desk Request Form" --json # fields, scripts, languages, PRDs that bind it
bin/idm prd.list tree/ --driver "User Application Driver" # status, category, json-forms/classic, bound forms
bin/idm prd.show tree/ HelpdeskTicket # properties, bindings, workflow activitiesform.show accepts a bare name (searched across every driver's provisioning),
<kind>/<name> (request/approval/template), or <driver>/<kind>/<name>
when names collide. A form is referenced by name from a PRD's
form-binding; form.show/prd.show cross-reference the two so you can see
a field's shape and everywhere it's used in one place.
Changing a form is a transaction like any other, and every form transaction re-syncs the PRD bindings that reference the form (Designer's own rules — the request form's field list is rebuilt from the components; data items are the persisted mappings and are kept or pruned, never invented, so a new field needs an explicit mapping step):
bin/idm form.edit tree/ "Help-desk Request Form" --check # which vendor builder would run; one-time fixes if any
bin/idm form.edit tree/ "Help-desk Request Form" # a person: opens the vendor form builder; on save+close → stored + bindings synced
bin/idm form.set-content tree/ --form "Help-desk Request Form" --content-file new.json # an agent: same result without a GUI
bin/idm form.sync tree/ --form "Help-desk Request Form" # after a builder saved into the tree with --no-waitThe form is stored pretty-printed (readable diffs); the deployer and the
Designer writer emit the compact form the vendor tools use. Editing one of the
11 stock forms or a stock PRD is allowed: it is marked customized and its
pre-edit document is baselined under .package-baseline/, exactly like a
packaged policy.
For a change an agent can make without the GUI, use the typed operations
(form.add, form.field.add/set/remove/move, form.set, form.localize,
form.rename, form.delete, prd.map, prd.add, prd.delete) — same
transaction machinery (--dry-run, --force, --json, validate after
every write). A
common recipe, add a field to a request form and map it to flowdata:
bin/idm form.field.add tree/ --form "Help-desk Request Form" --key priority --type select \
--label Priority --required --props '{"data":{"values":[{"label":"High","value":"high"},{"label":"Low","value":"low"}]}}'
bin/idm prd.map tree/ --prd HelpdeskTicket --field priority # default target: flowdata.Start/Help-desk_Request_Form/priority
bin/idm validate tree/ # 0 errors expected (FormCheck runs by default)form.field.add places the field at the end of components by default, or
next to another field (--after/--before/--first) or inside a named
container/columns component (--in); it starts from the captured builder
template for that type when one exists (resources/forms/components/) so a
form we author round-trips through the vendor builder unchanged, or the
minimal {label,key,type,input} shape with --minimal (what the IDM 4.10.1
stock forms actually use). prd.map is the one binding-sync never does on its
own — a new field starts unmapped until the agent explicitly maps it (or maps
an approval activity's data item with --activity); everything else about
keeping the PRD in step (rebuilding the request field list, pruning a mapping
whose field disappeared) happens automatically on every form-changing
operation. FormCheck (part of the standard validator) flags a document with
no components, a duplicate or missing key, an unknown component type, a
conditional/logic reference to a key that doesn't exist, a script that
doesn't compile, a request form with no button, incomplete localization, and a
PRD binding/mapping that's stale, drifted, or unbound.
To look at a form before deploying it, without the Identity Applications:
bin/idm form.preview tree/ "Help-desk Request Form" --out helpdesk.html # self-contained page: open-source Form.io renderer + placeholders for NetIQ componentsIt is a layout and conditional-logic check (live data sources are shown as
"not fetched"), not the vendor renderer. Deploying forms and PRDs is the
normal vault.diff → vault.deploy → verify path; no driver restarts, and
the plan says when the Identity Applications may need a cache flush.
A PRD's <process> — the workflow the Identity Applications actually runs —
reads as a typed view without hand-parsing XML:
bin/idm prd.flow tree/ HelpdeskTicket # header + a walk of the graph from start, activity by activity
bin/idm prd.flow tree/ HelpdeskTicket --format mermaid --out flow.mmd # a flowchart another tool (or a person) can renderThe text form walks the activity graph breadth-first from start-activity
following links (an activity no link ever reaches — a broken process — is
still listed, tagged (unreachable)), printing each activity's kind, display
name, the attributes that matter for its kind (timeout/approver-type/addressee
for an approval, the expression for a condition, category/operation for a
provisioning step, …) and its outgoing links, then every activity's data
items. --format mermaid emits a flowchart TD instead. Neither needs the
Identity Applications, Designer, or a live vault.
validate (on by default, FlowCheck) mirrors the workflow engine's own ten
load-time checks (ModelFactory.loadProcessFlow / ProcessFlowModel.validate()
— see docs/workflows.md §1.2) against every PRD's <process>: known process
version, exactly one start/finish, every link's endpoints and type valid for
its source activity's kind, a condition has both a true and false link, no
dangling activity, a branch has its merge, RBAC/RBACSOD/Resource processes
bind both outcomes, every flowdata. reference is .get(/.getObject(,
every approval has an addressee, notify/confirm/reminder have a
template — plus checks the engine doesn't run at all but that catch a broken
workflow before deploy: attribute enums, an addressee/expression/data-item
source that doesn't compile as ECMAScript, a leftover {enter … here}
template placeholder (warning on an Active PRD, informational on a template),
and an activity with no display name. docs/workflows.md §1.4 has the full
rationale; commands.md lists every flow-* code.
Changing the flow itself — not just a form's fields — is the flow.* typed
operations (commands.md has the full list): one op per concept
(flow.activity.add/set/rename/remove, flow.branch.add/remove,
flow.link.add/remove/retype, flow.data.set/remove, flow.set), each a
transaction like every other edit here (--dry-run, --force, --json,
validate after every write — a change FlowCheck would newly flag is
refused before it is written, same as prd.map/form.field.add). A common
recipe — start from NoApproval (the simplest stock template: start → grant
an entitlement → finish), replace its provisioning step with a condition and
a two-step approval, then look at the result:
bin/idm prd.add tree/ --name "Widget Access" --from-template NoApproval --request-form "Widget Request Form"
bin/idm flow.activity.remove tree/ --prd "Widget Access" --id prov # drop the stock grant step
bin/idm flow.activity.add tree/ --prd "Widget Access" --kind condition --id needs_reason \
--after Start --expression "flowdata.get('reason') != null"
bin/idm flow.activity.add tree/ --prd "Widget Access" --kind approval --id approval_1 --after needs_reason --via true \
--addressee "IDVault.get(recipient,'user','manager')"
bin/idm flow.activity.add tree/ --prd "Widget Access" --kind approval --id approval_2 --after approval_1 --via approved \
--addressee "'cn=uaadmin,ou=sa,o=data'"
bin/idm prd.map tree/ --prd "Widget Access" --field reason # bind the request form's field to flowdata
bin/idm validate tree/ # 0 errors, 0 flow-placeholder expected
bin/idm prd.flow tree/ "Widget Access" --format mermaid --out flow.mmd # review the shape before deployingflow.activity.add --after Y inserts the new activity into Y's single
outgoing link (or the one named by --via, when Y has more than one — the
op refuses and names the choices otherwise) and wires the new activity's own
default outgoing link(s) for its kind (an approval's approved/denied, a
condition's true/false, everything else's forward) — so the graph is
always dangling-free and validates clean right after the op, without a
separate flow.link.add. Parallel work is flow.branch.add (a branch/merge
pair) followed by flow.activity.add --after <branch> --to <merge> for each
leg. An approval's stock shape (timeout, default addressee, notify
template+maps, retry) and a provision activity's five entitlement data items
come from the same idm254 templates prd.add --from-template copies from
(TemplateSingleApproval_TD, NoApproval) — see commands.md. Once the
flow reads right, deploy it the normal way: vault.diff → vault.deploy.
flow.activity.add's four other kinds — rest, role-request,
resource-request, start-flow — call out to REST, role/resource requests
and other PRDs, and were calibrated (docs/workflows.md §4 W3) against the
engine's JAXB binding classes alone (no stock PRD uses any of them, so there
is no example to copy a shape from). Add one the same way as any other
activity, kind-specific flags after --kind:
bin/idm flow.activity.add tree/ --prd "Widget Access" --kind rest --id lookup --after Start \
--protocol https --host api.example.com --port 443 --path /v1/widgets --method GET \
--header "Authorization=Bearer TOKEN" --status-to statusCode --content-to body
bin/idm flow.activity.add tree/ --prd "Widget Access" --kind role-request --id grant_role --after lookup \
--role "'cn=Widget Users,ou=roles,o=data'" --target recipient --description "'Grant the Widget Users role'"
bin/idm flow.activity.add tree/ --prd "Widget Access" --kind start-flow --id follow_up --after grant_role \
--process "'Widget Follow-up'" --recipient recipient
bin/idm validate tree/ # flow-start-flow-unknown warns here: no PRD named "Widget Follow-up" exists yetflow.activity.set takes the same kind-specific flags to update an existing
activity of that kind (a flag that doesn't match the activity's kind is
refused, naming it); a repeatable one (--header/--role/--target/
--param/--recipient) replaces the whole list when given. These four kinds
have no live proof yet — trying one for real needs a REST endpoint or a role
on the lab (docs/workflows.md §4 W3).
A provision activity's DirXML-Entitlement-DN (above) has to name something
real for a grant to do anything — docs/entitlements.md covers the model.
An entitlement is a DirXML-Entitlement object hanging directly off the
driver (cn=<name>,cn=<driver>,<driver set>), not under AppConfig, so it
lives at drivers/<driver>/entitlements/<name>.xml in the tree and rides the
normal vault.diff/vault.deploy (no driver restart — the Identity
Applications read it from the vault at grant time):
bin/idm entitlement.add tree/ --driver Loopback --name TestAccess --display-name Group --multi-valued --values a,b
bin/idm flow.activity.add tree/ --prd "Widget Access" --kind provision --id prov --after approval_2 --via approved \
--entitlement-dn "cn=TestAccess,cn=Loopback,cn=driverset1,o=system"
bin/idm validate tree/ # flow-entitlement-unknown/-external if the DN doesn't resolveentitlement.remove refuses while any PRD's provision activity still names
it (--force never overrides that — repoint or remove the activity first).
entitlement.list/entitlement.show orient; EntitlementCheck validates
the document itself (root element, conflict-resolution, multi-valued);
FlowCheck cross-checks a provision activity's DN against the tree's
drivers. See commands.md for the full flag list.
Everything else under the User Application driver's AppConfig is in the tree as
provisioning/objects/<path>.xml (docs/appconfig.md). Read with
appconfig.list / appconfig.show; edit with the typed operations:
bin/idm role.add tree/ --name Auditor --level 20 --category Custom --display "Auditor" --display "de=Prüfer" --descr "Audits access"
bin/idm resource.add tree/ --name AuditGroup --category Custom --entitlement "cn=Groups,cn=AD,cn=driverset1,o=system" --param "cn=auditors,ou=groups,o=data"
bin/idm entity.attr.add tree/ --entity user --key roomNumber --ldap roomNumber --display "Room" --required true
bin/idm appconfig.set tree/ --path UIConfig/NavItems/AccessRptTool --attr nrfLocalizedNames --value "de=Zugriffsbericht"
bin/idm role.remove tree/ --name Auditor
appconfig.add/set/remove work on any object; the guards are the vault's:
runtime containers are never touched, an object that holds objects or is
named by another's DN is not removed, a packaged one needs --force, and the
operational attributes (equivalentToMe, DirXML-Associations) are refused.
A packaged object's first edit gets a baseline and the customized mark, as a
form's does; package.revert tree/ --path <tree path> puts any customized
packaged thing back (content, mark and the package's checksum). Deploy as always: vault.diff shows the objects, vault.deploy
writes only the changed attributes.
When a person wants to read a trace rather than have it summarised, open the
desktop viewer for them: driver.trace view --env <env> --driver <D> streams
live in the DirXML Trace Viewer, driver.trace view --file <trace> opens a
file (viewer.install first, once; viewer.check says whether it is there).
It is read-only and separate from what you read yourself with tail.
To make a driver fully custom — no package ever installed it, as far as the
tree, the vault and Designer can tell — package.strip tree/ --driver D
removes every stamp, mark and baseline under the driver and marks it stripped;
the next vault.deploy then deletes the vault's stamps and package aux classes
too (docs/packages.md §3.7). Library items are shared, so they need --library.
Content — the rules inside a policy, a stylesheet, a script, a table's rows: edit the file. DirXML Script is the language; the engine's compiler judges it:
$EDITOR "tree/drivers/AD Driver/subscriber/sub-ctp-Transform.policy.xml"
bin/idm validate tree/Structure — anything that touches more than one file or the linkage: use an operation. Each loads the tree, applies the change, validates, and writes only if it introduced no new error; otherwise it refuses and writes nothing.
bin/idm policy.add tree/ --driver "AD Driver" --scope subscriber --name sub-ctp-NormalizeTitle \
--link subscriber-command --at "after:drivers/AD Driver/subscriber/sub-ctp-Transform"
bin/idm rule.add tree/ --path "drivers/AD Driver/subscriber/sub-ctp-NormalizeTitle" \
--content-file rule.xml --at last
bin/idm artifact.rename tree/ --path "library/LocCodeMap" --name LocationCodeMap
bin/idm gcv.set tree/ --driver "AD Driver" --name drv.user.container --value "data\users"
bin/idm filter.set-attr tree/ --driver "AD Driver" --class User --attr Title --publisher sync --subscriber sync
bin/idm mapping-table.set-row tree/ --path library/LocationCodeMap --col LocCode=0042 --col Domain-Placement="OU=x,DC=y"Every operation takes --dry-run (do everything but write; the result shows
what would change), --force (write despite new errors — say why in the commit),
and --json (the same result as data: ok, written, touched, renamed,
customized, changedFiles, deletedFiles, newErrors, and the full
validate report).
Read a refusal as information, not an obstacle:
| refusal | it means |
|---|---|
'…' is still referenced — link from drivers/X (set …); include from … |
delete would leave a dangling reference; --unlink drops policy-set links, but an <include> or a Map token is content — fix that policy first |
would introduce N validation error(s) |
the engine would refuse to load the result; the listed errors are its diagnostics |
GCV 'x' is not defined … add --define <type> |
you're setting a GCV nothing defines; create it deliberately |
GCV 'x' is read by … policies |
deleting it would stop the driver from starting |
'x' names 2 rules; use #n |
duplicate descriptions — address the rule by position |
Overriding a policy that came from a package is normal. The first operation
that touches one keeps its pre-edit content in .package-baseline/ and marks it
package.customized in the manifest; the result says customized (packaged; baseline kept). Later:
bin/idm package.diff tree/ "drivers/AD Driver/subscriber/NOVLADDCFG-sub-ctp-EntitlementsImpl"shows exactly what was customized. Commit the baseline with the change. (The vault-side "modified" mark is set by the deployer when it writes the object.)
New drivers are authored in the tree, not in Designer. Three sources:
bin/idm driver.add tree/ --name "AD Driver 2" --from-export ad-export.xml # a vendor/package export (driver-set form keeps Library scope)
bin/idm driver.add tree/ --name "AD Driver TEST" --copy-of "AD Driver" # a deep copy: artifacts, config and links re-pointed
bin/idm driver.add tree/ --name Loop --shim-class com.example.Shim # blank: channels, empty filter, no policiesThe operation is a transaction like the others: the new driver must validate
in this tree, so an export whose GCVs are defined at the driver-set level of
its origin will be refused until those GCVs exist here (define them first with
gcv.set --define). Deploy it like any other change; the deployer creates the
objects and refuses until the driver's required secrets are in the environment's
secrets file (or --allow-missing-secrets).
Packages are Designer's unit of vendor and custom content. DirXMLDev keeps its own catalog (a git directory of package jars) and installs, inspects and builds packages without Designer (packages.md):
bin/idm package.fetch --catalog ~/idm-packages --short NOVLADBASE # newest version; --all-versions for every one
bin/idm package.import --catalog ~/idm-packages /Applications/Designer/packages/eclipse/plugins # or a Designer install
bin/idm package.show --catalog ~/idm-packages NOVLADBASE
bin/idm package.resolve --catalog ~/idm-packages --base NOVLADBASE --feature NOVLADDCFG
bin/idm driver.add tree/ --name "AD Driver" --catalog ~/idm-packages --package NOVLADBASE,NOVLADDCFG --answers ad.properties
bin/idm package.install tree/ --catalog ~/idm-packages --package NOVLADENTEX --driver "AD Driver" --answers ad.properties
bin/idm package.status tree/ --catalog ~/idm-packages # installed, customized, newer versions
bin/idm package.build --catalog ~/idm-packages tree/ --driver "AD Driver" --short PBTADCUST --name "AD customizations" --vendor pointbluetech
bin/idm package.site --catalog ~/idm-packages --out /var/www/packages # an update site Designer users can addAn install is a transaction like any other edit, and reproduces Designer's
install exactly (prompts, placement, weights, stamps); the deployer writes
the package stamps to the vault, so Designer sees the packages when it
imports. A refusal naming mandatory prompts lists what the answers file
needs. Content that references GCVs another package defines installs in
the same transaction as that package (--package a,b,c). A tree imported
before package stamps were read needs package.adopt (or a fresh
import-live).
bin/idm validate tree/ # engine will load it
bin/idm simulate tree/ --cases cases/ --against /path/to/tree-before # another as-code tree, not a git rev
git add -A tree/ && git commit -m "AD: normalize Title on subscriber command (#123)"simulate runs the client's regression cases (harvested with the simulator's
harvest, or authored) against the edited tree and diffs them against the
previous tree — an output that changed is shown, never hidden.
Vault targets live in a gitignored environments.properties (path in
IDM_ENVIRONMENTS; see vault-deploy.md); secrets the tree
can't carry in a gitignored secrets file per environment.
bin/idm vault.diff tree/ --env stg # what differs, per object; exit 1 if anything
bin/idm vault.deploy tree/ --env stg --driver "AD Driver" --dry-run # the plan, nothing written
bin/idm vault.deploy tree/ --env stg --driver "AD Driver" --yes # snapshot → write → restart → verify → audit
bin/idm vault.deploy tree/ --env stg --step # or: confirm and verify each change
bin/idm vault.verify tree/ --env stg # re-read: vault == tree
bin/idm vault.rollback --env stg --snapshot deploy-snapshots/stg/<ts>.ldif --yesWhat the deployer will not do: write anything the tree doesn't validate
clean; delete a driver (it reports one the tree lacks); restart a stopped
driver (it loads the new configuration when started); touch a secret unless
the driver is new or you pass --secrets all|missing; deploy to a prd tier
without --confirm <env>, a committed tree, and a vault that matches the last
recorded deploy (or --capture-drift, which records the vault's current state
on an as-found/<env>/<ts> branch for you to merge first). Every deploy
appends to deploy-log/<env>.jsonl — commit it with the tree.
bin/idm driverset.status --env stg # every driver: state, start option, cache bytes, trace
bin/idm driver.status --env stg --driver "AD Driver" # + trace file, named passwords, recent audit
bin/idm engine.stats --env stg --driver "AD Driver" # JVM heap/threads + cache and operation counters
bin/idm driver.cache view --env stg --driver "AD Driver" --out cases/ad-cache # queued events → a simulator case
bin/idm driver.trace tail --env stg --driver "AD Driver" --since 10 --grep "Applying rule"
bin/idm driver.restart --env stg --driver "AD Driver" --yes
bin/idm driver.stop --env stg --driver "AD Driver" --yes
bin/idm driver.trace set --env stg --driver "AD Driver" --level 3 --file /var/opt/novell/eDirectory/log/ad.trace --yes
bin/idm driver.submit --env stg --driver "AD Driver" --xds event.xds --yes --tree tree/ # the canary
bin/idm driver.cache clear --env stg --driver "AD Driver" --yes --confirm stgGating follows what an operation can break (operate.md): reads
(status, cache view, trace show/tail, secrets list, engine.*) are free;
start, restart, trace set/reset, and secrets set/remove need --yes on stg
and --yes --confirm <env> on prd; stop, resync, migrate, and submit need
--yes on every tier and --confirm <env> on prd; cache clear prints the
count and first/last event, saves the events to deploy-snapshots/, and
needs --yes plus --confirm <env> on stg and prd. Every state change is
audited. driver.submit --tree is the ground truth for a
policy change: the live engine's Subscriber channel hands the shim a document,
the trace shows which, and the simulator's prediction from the tree must match
it.
Teams that keep a Designer project get it updated from the tree, not re-imported:
bin/idm export-project tree/ ~/designer_workspace/Client --dry-run # what it would touch
bin/idm export-project tree/ ~/designer_workspace/Client # writes; result lists created/changed/deleted files
bin/idm docs tree/ --out docs/ --since HEAD~5 # README, one page per driver, library, changesThe writer edits only the files the diff calls for: a changed policy rewrites
its _contents.xml; an added one gets a new 8-character id, its CObject and
contents files, and a Child relation on its owner; a removed one loses its
files and every relation that pointed at it; a rename keeps the id; linkage
rewrites the ordered relations on the driver or channel. Everything else in
the project is byte-identical afterwards. It refuses a driver that carries
package metadata (Designer's catalog owns those; deploy to the vault and
import there, or write a whole new project with --new below) and never
deletes a driver. Commit the project after it runs and open it in Designer
once before trusting a new kind of change.
When there is no Designer project (the tree came from import-live, or the
team wants one without pointing Designer at the vault), write a whole one:
bin/idm export-project tree/ ~/designer_workspace/Client --new --dry-run
bin/idm export-project tree/ ~/designer_workspace/Client --new \
--vault-name IDM_TREE --vault-host vault.example.com --vault-user cn=admin,ou=sa,o=system \
--server idm-engine --server-context ou=servers,o=systemThe directory must not exist, or be empty — its basename is the project
name, and it is written into .project, <name>.proj and <name>.cproj
(a mismatch is what gives Designer "No valid .proj file" or a silent, empty
import, so never rename a project folder by hand afterwards). Everything the
tree holds is written: the driver set, the Library, every driver with its
channels, filter, policies, resources and GCVs, each driver's Application_
and modeler node, the User Application driver's whole AppConfig (forms and
PRDs) and its entitlements. The vault and server flags are all optional, and
no vault password is ever written (IdentityVaultSavePassword=false) —
Designer asks for it on the first connect.
Packaged items are written with their package attributes and an
<id>_initial_state.xml baseline, but the project's package catalog
(IdmPackage_ objects, Idm:InstalledPackages relations) is milestone N3:
the result note lists the packages the tree names, and until the catalog
exists Designer treats those items as plain. --new never touches an
existing project; drop the flag to update one.
- One operation or one content edit per commit, with the result's file list in
the message;
--jsonoutput is fine to paste. - Never hand-edit
driver.xml/library.xml/driverset.xmlmanifests — that's what the operations are for. - Never delete
.package-baseline/entries; they're the record of every override. - Don't run two operations on the same tree concurrently.
- Client trees hold client policy: they live in the client's repo, never here.