@nexvar/huly
v1.0.0
Published
CLI for the Huly Platform API with JSON-first output
Readme
huly-cli
huly-cli is a JSON-first command line client for the Huly Platform API, aimed at scripts, CI jobs, and AI agents that need predictable shell commands instead of ad hoc TypeScript snippets.
The project exposes the Huly platform client through dedicated first-class commands plus the generic raw layer for the remaining document, collection, mixin, and markup operations.
Priorities
- Performance-first CLI execution
- Predictable JSON output for automation and AI agents
- Current stable TypeScript baseline and modern Node.js compatibility
- Compatibility with both Huly cloud and self-hosted deployments
Implemented Scope
Current Phase 1 commands:
auth login|status|logoutproject list|get|create|update|deleteissue list|get|create|update|delete|template list|get|relation add|relation remove|blocker add|blocker removemember list|me
Additional implemented commands:
teamspace list|get|create|update|deletedoc list|get|create|update|deleteperson list|get|create|update|deletemilestone list|get|create|update|deletelabel list|get|create|update|assign|unassign|deletecomponent list|get|create|update|deletechat list|get|create|update|deletechat direct get|createchat member list|add|removechat message list|get|send|update|deletechat thread list|get|send|update|deletecomment list|addboard list|get|create|update|deleteboard status listboard column list|getboard card list|get|create|update|move|deletecard types|type list|get|create|update|delete|role list|get|create|update|delete|list|get|create|update|move|deletedrive list|get|create|update|deletedrive activitydrive folder list|get|create|update|delete|activitydrive file list|get|create|update|delete|activityhr department list|get|create|update|deletehr employee list|gethr public-holiday list|get|create|update|deletehr request-type listhr request list|get|create|update|deletenotification list|get|read|unread|archive|unarchiveraw list|get|create|update|delete|add-collection|update-collection|remove-collection|create-mixin|update-mixin|fetch-markup|upload-markuprecruit vacancy list|get|create|update|deleterecruit applicant-status listrecruit applicant list|get|create|update|move|deleterecruit candidate list|get|create|update|deleterecruit review list|get|create|update|deleterecruit opinion list|get|create|update|deletetime list|get|create|update|done|open|deletetime report list|get|totals|create|update|delete
Current scope details:
- Implemented:
auth,project,issue,member,teamspace,doc,person,milestone,label,component,comment,board,card,chat,drive,hr,notification,raw,recruit,time - The CLI combines dedicated namespaces with
rawcoverage for the remaining generic platform-client operations.
Current raw scope:
rawprovides low-level document, attached-collection, mixin, and markup access for automation when a dedicated higher-level namespace is not available yet.rawnow supportslist|get|create|update|delete,add-collection|update-collection|remove-collection,create-mixin|update-mixin, and directfetch-markup|upload-markuphelpers.raw upload-markupattaches the uploaded markup back to the target field by default; use--upload-onlywhen you want only the standalone markup ref.- Raw JSON payloads now support markup-backed fields through objects shaped like
{ "$markup": { "format": "markdown", "content": "..." } }. raw getandraw listalso support--markup-fieldsso callers can resolve selected markup attributes inline instead of only seeing blob refs.- The main remaining
rawlimitation is discovery ergonomics: callers still need to know the relevant class, space, collection, mixin, and markup attribute ids.
Current time scope:
timecurrently manages issue-attached todos plus issue-attachedTimeSpendReportentries through Huly's published time and tracker packages.- Time-report CRUD plus
time report totalsare implemented and intended for automation-friendly logging and rollups against tracker issues. - The current totals view returns overall hours plus issue, day, and employee groupings from the matching report set.
time listnow supports exact--title, exact--priority, and due-date range filters through--due-date-from/--due-date-to.time report listandtime report totalsnow support exact--descriptionplus numeric--value-from/--value-tofiltering.time updatenow supports both--clear-descriptionand--clear-due-datefor todos,time report updatesupports--clear-descriptionfor report notes, and todo due dates follow the same ISO-8601 validation path as the rest of the CLI.- Higher-level time-reporting ergonomics can still grow, but the current
timecommands plusrawalready cover the reachable operation surface.
Current card scope:
cardcurrently manages cards in Huly's default card space, custom card type CRUD, and attached role CRUD for workspace-defined types.- Built-in card types remain readable but intentionally read-only. Custom
card typeandcard rolewrites are smoke-tested live. - Custom
card type create|updatenow supportcolor,background, andremovedmetadata on workspace-defined types, andcard type updatesupports explicit--clear-color/--clear-backgroundflows. - Generic cards now support exact
card list --title, parent assignment on create, parent changes throughcard update --parent|--clear-parent, root filtering throughcard list --root, readonly/editable filtering throughcard list --readonly|--editable, and sibling reordering throughcard move --before|--after|--top|--bottom. - The smoke-tested card create/update/delete path still uses the generic
Cardtype. Other workspace-specific card types are discoverable and targetable, but some may have stricter backend behavior. - Higher-level card-schema ergonomics can still grow, but uncovered card docs and attributes are reachable through
raw.
Current chat scope:
chatcurrently manages chat channels, direct-message lookup/creation, channel membership updates, chat messages, and thread replies attached to chat messages.- Channel CRUD is smoke-tested.
chat listnow supports exact--name,--member,--private,--public,--archived, and--activefiltering, plus--channel/--directkind filters, andchat updatesupports explicit--clear-topic/--clear-descriptionflows. Channel member list/add/remove is smoke-tested live with disposable channels. Message create and delete are smoke-tested. Message updates use bounded settle polling before returning, but freshchat message getreads can still lag after an update on the Huly backend. - Direct-message lookup/creation by member email is smoke-tested live. Thread reply list|get|send|update|delete is also smoke-tested live against disposable channels. Additional chat ergonomics can still be added, but uncovered chat docs remain reachable through
raw.
Current issue scope:
issuenow surfacesestimation,remainingTime, andreportedTimein issue output, and supports--estimation/--remaining-timeonissue createandissue update.issue listnow supports repeated--statusfilters plus--date-from/--date-todue-date filtering for broader tracker automation.- Live smoke confirmed these fields round-trip, but Huly recalculates
remainingTimewhenestimationchanges. The CLI reports the backend result rather than pretending independent control over both fields. issuealso surfaces relation/blocker ids and identifiers, derived child/template metadata, and supportsissue relation add|removeplusissue blocker add|remove.issue template list|getis implemented for published tracker templates. Live reads against the current workspace returned empty lists, so templategetremains verified only at the code-path level until real template data exists.
Current milestone / label / component scope:
milestonenow supports full CRUD within tracker projects, including directgetby id and verified live deletion of disposable milestones.labelnow supports full CRUD for issue labels pluslabel unassign, with delete removing attached tag references before deleting the label record.componentnow supports full CRUD with markdown description round-tripping and duplicate-label protection within a project.
Current doc / teamspace / person scope:
docsupports list|get|create|update|delete within teamspaces, exactdoc list --title,--parent, and--rootfiltering, parent assignment ondoc create --parent, and hierarchy moves throughdoc update --parent|--root.Document create now uses bounded read-after-write polling before returning, because live smoke exposed backend lag when reading a freshly created doc immediately.
Live smoke verified nested document hierarchy flows in a disposable teamspace, including parent create, root/parent/title filtering, moving a child doc back to root, and cleanup.
teamspacenow supports full CRUD with privacy/archive toggles, explicit description clearing, and exactlistfilters for--name,--private,--public,--archived, and--active. Live smoke verified create|get|update|delete plus the new list filters against disposable teamspaces.personnow supports full CRUD with email-channel synchronization, exactlistfilters for--name,--city, and--email, plus--clear-cityand--clear-emailsemantics on update. Live smoke verified create|get|update|delete, exact list filters, and attached email cleanup.
Current board / drive scope:
boardsupports list|get|create|update|delete against workspace spaces,board column list|getas derived views of live card-status groupings, andboard card list|get|create|update|move|deletefor board-attached cards.- Board create/get/update/list now round-trip the published
Board.colorandBoard.backgroundmetadata in addition to name/description/privacy/archive fields, and board update supports explicit--clear-color/--clear-backgroundflows. board listnow supports exact--name,--private,--public,--archived,--active, and--limitfiltering.- Board-card writes use the verified attached-document path on
board.class.Board -> cards, with markdown description support, published cover metadata (cover.color/cover.size), member employee refs, start/due date, location, archive-state updates, assignee round-tripping through person ids, status round-tripping through Huly status refs, and explicit rank-based reordering. board card listsupports exact--title, exact--location,--status, assignee, member, and--archived/--activefiltering, returns rank-ordered cards when scoped to a board,board card create|updatesupport explicit status ids, assignee person ids, cover metadata, and comma-separated member employee ids,board card updateclears cover/members/location/start-date/due-date through explicit flags plus Commander-safe--no-*handling, andboard card movenow supports before/after/top/bottom ordering plus optional status changes, including inheriting the target card status on cross-column moves.board column listgroups current cards by status with friendly status/category names when the referenced model status exists, andboard column get --board ... (--status ...|--without-status)returns one derived column plus a rank-ordered card sample for that column.board status listreturns status ids currently used by board cards (optionally scoped with--board) with resolved names/categories plus card counts.drivesupports both workspace drive spaces and lightweight folder/file record CRUD through backend document refs. File activity history is smoke-tested live with disposable resources and cleanup.drive listnow supports exact--name,--private,--public,--archived,--active, and--limitfiltering.drive folder list/drive file listnow support exact--title,--name, and--limitfiltering for lightweight record lookups.drive updatenow supports--clear-description, anddrive folder update/drive file updatenow support--clear-namefor lightweight record cleanup flows.drive activity,drive folder activity, anddrive file activityread attachedactivity:class:DocUpdateMessageentries, which gives a safe verified history surface while dedicated drive blob/content ergonomics remain a separate follow-up.drivecurrently targets backend document refs directly because the drive npm package is not published on npm even though the backend namespace exists and is usable live.
Current hr scope:
hrcurrently supports department CRUD, employee list|get, public-holiday CRUD, request-type list, and request list|get|create|update|delete.- Public holiday CRUD uses the published HR package model in
core:space:Workspace; create defaults tohr:ids:Headwhen--departmentis omitted, and public-holiday list now supports exact--titleplus--date-from,--date-to, and--limitfiltering. Request creation uses the correct attached-doc path and defaults to the current authenticated member when--employeeis omitted. Request list now supports--employee,--department,--type,--date-from,--date-to,--due-date-from, and--due-date-to, with day-bucket comparisons that match Huly'stzDatebehavior. Request update now supports--clear-due-date. - Department update now safely clears parent and team lead through Commander-safe
--no-parentand--no-team-leadhandling. These flows were smoke-tested live against the current workspace, including request type resolution and cleanup. - Department, public-holiday, and request update now support explicit
--clear-descriptionflows.
Current notification scope:
notificationsupportslist|get|read|unread|archive|unarchivefor inbox notifications scoped to the current authenticated account.notification listnow supports exact--class,--object-class,--object-id, and--typefilters in addition to the existing--read|--unread|--archived|--activeflags.- Live smoke verified the new read-only filters against existing real inbox notifications without mutating company data.
Current recruit scope:
recruitcurrently supports vacancy CRUD, applicant-status list, applicant list|get|create|update|move|delete, candidate list|get|create|update|delete, review list|get|create|update|delete, and opinion list|get|create|update|delete.- Vacancy, applicant, review, and opinion writes use backend-validated payload shapes discovered through live smoke rather than guessed package-level abstractions. Vacancy update now round-trips
fullDescriptionand supports--clear-full-description,--clear-location, and--clear-due-date. Vacancy list now uses backend exact-match filtering for--name,--location,--private,--public,--archived, and--active, including the archived-awareshowArchivedpath required by Huly's list API. Review creation follows Huly's calendar-event payload requirements, and opinion CRUD uses the verifiedReview -> opinionsattached collection path. - Applicant statuses are resolved from the published recruit task type instead of hard-coded display labels, applicant summaries now expose
statusIdandrank, applicant list supports vacancy, exact--identifier, status, assignee, and unassigned filtering for lifecycle automation, and vacancy-scoped applicant ordering is rank-sorted when filtering by vacancy. Applicant update safely clears assignee/start-date/due-date through Commander-safe--no-*handling, and applicant move now supports--before|--after|--top|--bottomplus optional status changes while preserving same-vacancy safety. Candidate CRUD is implemented by creating/updating contact persons with the recruit candidate mixin; candidate list now supports exact--name,--city,--title,--source,--remote, and--onsitefilters, review list supports exact--verdictand exact--location, opinion list supports exact--value, and candidate update supports clearingcity,title, andsourceplus explicit--no-remote/--no-onsitetoggles. - Vacancy summaries now protect
applicantCountagainst backends that return unknown totals by falling back to bounded count reads, so counts do not degrade to sentinel negative values. - Review and opinion descriptions use the shared markup update path that was already fixed for other markdown-backed entities, so description create/update round-trips are verified live, including explicit
--clear-descriptionupdate flows. Review due dates remain settable but do not expose a clear flag yet, because a live null-update probe kept the previous backend value.
Verification snapshot:
- Local verification:
npm run build,npm test - Repeatable built-CLI verification:
- Run
npm run build,npm test,npm run smoke. - Prerequisites: valid auth via environment, local config, or
.env, and a builtdist/fromnpm run build. npm run smokeruns against the current live workspace, includes an isolated token authlogin|status|logoutround-trip in a temporary home directory, uses disposablecli-smoke-auto-*resources, snapshots the built CLI into.omx/smoke-runs/, and cleans everything up after the run.
- Run
- Live verification: built CLI auth via token, project CRUD, teamspace/person CRUD plus exact list filters, clear flows, and cleanup, nested doc hierarchy create/list/update/delete flows in a disposable teamspace, milestone/label/component CRUD plus label assign/unassign cleanup, board column/status flows plus board list
--limit, board-card title/location/archived-state filters, status-aware move flows, member filtering, and cleanup, card parent/move flows plus custom card-type--clear-color/--clear-background, chat channel exact name/member/kind/private/public/archived filters plus--clear-topic/--clear-description, drive list--limit, drive space/folder/file activity reads plus drive space clear-description, drive folder/file clear-name flows, and drive folder/file exact title/name list filters with cleanup, hr department clear-parent/team-lead plus clear-description flows, hr public-holiday title/date/limit plus clear-description flows, hr request clear-due-date plus clear-description flows, read-only notification class/object/type filters against the real inbox, recruit vacancy full-description plus private/public/archived/active filters and applicantCount validation, recruit applicant identifier/filter/clear/move flows, recruit candidate exact name/city/title/source/remote/onsite filters, recruit review verdict/location filters, recruit opinion value filters, recruit candidate/review/opinion CRUD including candidate clear/toggle flows and review/opinion clear-description flows with cleanup,time listtitle/priority/due-date-range filters,time report listdescription/value-range filters,time report totalsdescription/value-range filtering,time update --clear-description|--clear-due-date,time report update --clear-description, andtime report totalsday-bucket aggregation with--date-fromfiltering - Live verification also now covers
raw fetch-markup,raw update-collection,raw remove-collection,raw create-mixin, andraw update-mixinagainst disposable document, card-role, and recruit-candidate targets. - The README reflects verified commands only.
Install
npm install
npm run buildInstall from npm after publish:
npm install -g @nexvar/hulyRun without global install:
npx @nexvar/huly --helpTooling baseline:
- Node.js
>=20 - TypeScript
5.9.x
Run from source:
npm run dev -- auth statusRun the built CLI:
node dist/bin/huly.js project listJSON metadata output:
node dist/bin/huly.js --help
node dist/bin/huly.js issue --help
node dist/bin/huly.js --versionConfiguration
The CLI reads configuration in this order:
- Process environment variables
- Local
.env ~/.huly/config.json
Supported variables:
HULY_URL=https://huly.app
HULY_WORKSPACE=my-workspace
HULY_TOKEN=...
[email protected]
HULY_PASSWORD=secretExample .env:
cp .env.example .envToken-based auth is supported and is the fastest path for automation:
HULY_URL=https://huly.app
HULY_WORKSPACE=my-workspace
HULY_TOKEN=your-tokenLogin flow:
npm run dev -- auth login \
--url https://huly.app \
--email [email protected] \
--workspace my-workspace \
--password secretUsage
npm run dev -- project list
npm run dev -- issue list --project HULY --limit 10
npm run dev -- member me
npm run dev -- teamspace list
npm run dev -- doc list --teamspace "Quick-Start Docs"
npm run dev -- person list --limit 20
npm run dev -- milestone list --project WEBSI
npm run dev -- label list
npm run dev -- component list --project WEBSI
npm run dev -- chat list --include-direct --limit 10
npm run dev -- chat member list <chat-id>
npm run dev -- comment list --on WEBSI-123
npm run dev -- board card list --limit 10
npm run dev -- card list --type Card --limit 10
npm run dev -- notification list --unread --active
npm run dev -- time list --issue HULY-1
npm run dev -- time report list --issue HULY-1Using the built binary:
node dist/bin/huly.js auth status
node dist/bin/huly.js project get HULY
node dist/bin/huly.js issue get HULY-1
node dist/bin/huly.js board card list --limit 10
node dist/bin/huly.js teamspace list
node dist/bin/huly.js person list
node dist/bin/huly.js milestone list --project WEBSI
node dist/bin/huly.js label list
node dist/bin/huly.js component list --project WEBSI
node dist/bin/huly.js chat list --limit 10
node dist/bin/huly.js chat member list <chat-id>
node dist/bin/huly.js comment list --on WEBSI-123
node dist/bin/huly.js card list --type Card --limit 10
node dist/bin/huly.js notification list --limit 10
node dist/bin/huly.js time list --limit 10
node dist/bin/huly.js time report list --limit 10Create an issue:
npm run dev -- issue create \
--project HULY \
--title "CLI smoke test" \
--description "Created by huly-cli"Create a sub-issue:
npm run dev -- issue create \
--project WEBSI \
--title "Child task" \
--parent WEBSI-123Create an issue with time metrics:
npm run dev -- issue create \
--project WEBSI \
--title "Tracked task" \
--estimation 4 \
--remaining-time 2.5Update an issue milestone:
npm run dev -- issue update WEBSI-123 --milestone "Sprint 1"Update issue time metrics:
npm run dev -- issue update WEBSI-123 --estimation 6
npm run dev -- issue update WEBSI-123 --remaining-time 1.5List issue templates:
npm run dev -- issue template list --project WEBSI --limit 10Create and complete an issue todo:
npm run dev -- time create \
--issue HULY-1 \
--title "Follow up from CLI" \
--description "Created by huly-cli"
npm run dev -- time done <todo-id>Create and update a time report:
npm run dev -- time report create \
--issue HULY-1 \
--value 1.5 \
--description "Investigated and fixed the CLI path"
npm run dev -- time report update <report-id> --value 2 --description "Included verification"
npm run dev -- time report totals --issue HULY-1Create a board card with a status and inspect columns:
npm run dev -- board create --name "CLI board"
npm run dev -- board card create \
--board <board-id> \
--title "Board task" \
--status tracker:status:Todo
npm run dev -- board card list --board <board-id> --status tracker:status:Todo
npm run dev -- board column list --board <board-id>
npm run dev -- board card update <card-id> --status tracker:status:Done
npm run dev -- board card move <card-id> --top
npm run dev -- board card move <card-id> --after <other-card-id>
npm run dev -- board card update <card-id> --clear-statusCreate and reorganize cards:
npm run dev -- card create \
--title "Parent card"
npm run dev -- card create \
--title "Child card" \
--parent <parent-card-id>
npm run dev -- card list --parent <parent-card-id>
npm run dev -- card update <card-id> --clear-parent
npm run dev -- card update <card-id> --parent <new-parent-card-id>
npm run dev -- card move <card-id> --top
npm run dev -- card move <card-id> --after <sibling-card-id>Manage channel members:
npm run dev -- chat member list <chat-id>
npm run dev -- chat member add <chat-id> --member [email protected]
npm run dev -- chat member remove <chat-id> --member [email protected]Create a custom card type and role:
npm run dev -- card type create \
--label "CLI Smoke Type" \
--extends Card \
--color 11 \
--background 22
npm run dev -- card role create \
--type <type-id> \
--name "Blocks"Create a chat channel and send a message:
npm run dev -- chat create \
--name "cli-smoke-channel" \
--topic "CLI smoke"
npm run dev -- chat message send \
--chat <chat-id> \
--message "Hello from huly-cli"Create or fetch a direct-message chat:
npm run dev -- chat direct create --member [email protected]
npm run dev -- chat direct get --member [email protected]Reply in a chat thread:
npm run dev -- chat thread send <message-id> --message "Thread reply"
npm run dev -- chat thread list <message-id>Create a document:
npm run dev -- doc create \
--teamspace "Quick-Start Docs" \
--title "CLI notes" \
--content "# Notes"Create a person:
npm run dev -- person create \
--name "CLI Temp Contact" \
--city "Istanbul" \
--email "[email protected]"Create a milestone:
npm run dev -- milestone create \
--project WEBSI \
--label "Sprint 1" \
--status Planned \
--target-date 2026-04-15List or create labels:
npm run dev -- label list
npm run dev -- label create --title bug --color 11 --description "Bug reports"
npm run dev -- label assign WEBSI-123 --label bugList or create components:
npm run dev -- component list --project WEBSI
npm run dev -- component create --project WEBSI --label Backend --description "Backend services"List or add comments:
npm run dev -- comment list --on WEBSI-123
npm run dev -- comment add --on WEBSI-123 --message "Implemented in commit abc123"Work with inbox notifications:
npm run dev -- notification list --unread --active
npm run dev -- notification get 69b6f98faf221468336cced8
npm run dev -- notification read 69b6f98faf221468336cced8
npm run dev -- notification archive 69b6f98faf221468336cced8Output Contract
Success goes to stdout:
{
"ok": true,
"data": []
}Errors go to stderr with a non-zero exit code:
{
"ok": false,
"error": {
"code": "NOT_FOUND",
"message": "Issue 'HULY-42' not found"
}
}Exit codes:
0: success1: general error2: authentication error3: not found4: validation error5: connection error
--help and --version also return JSON on stdout, matching the CLI's machine-readable output contract.
Performance Notes
- Read-heavy commands avoid initializing transactional operations unless a write path is actually needed.
- The Node runtime uses the published Huly REST client plus transaction helpers, which avoids the browser-only WebSocket runtime path on modern Node releases.
- This keeps startup lighter for common read commands such as
project list,issue list, andmember me. label list --project <identifier>returns labels currently referenced by issues in that project, because Huly issue labels are workspace-scoped tags rather than project-owned records.- Connection bootstrap now retries transient network failures with a short exponential backoff instead of failing on the first dropped request.
- The build clears
distand excludes test files from the published tarball, which keeps the package leaner.
Implementation Notes
- Uses official published Huly packages, centered on
@hcengineering/api-client. - Issue creation follows Huly’s published sequence-and-rank workflow.
- Issue labels are implemented through Huly’s published
@hcengineering/tagspackage and attached to issues as tag references. - Components are implemented as tracker-scoped docs in the project space.
- Comments are implemented as
@hcengineering/chunterchat messages attached to the parent object'scommentscollection. - Notifications are implemented as
@hcengineering/notificationinbox docs scoped to the current authenticated account. - Document content is stored through the explicit markup upload path, which now works for both
doccontent and issue descriptions. removeDocis wired for issue deletion and passed live smoke tests. Additional cross-deployment verification is useful future evidence, not a current release blocker.- The current TypeScript/compiler setup is on the latest stable 5.9 line;
tsconfigmodernization for newer Node-specific compiler modes is a separate optimization step rather than a functional blocker.
