Skip to content

Latest commit

 

History

57 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

awork

The awork CLI — built for humans and agents alike

Token or OAuth authentication • Swagger-driven code generation • Structured JSON output

CI Release License .NET 10 OpenAPI 3.0


Why awork CLI?

Problem Solution
Unstable command names across API versions Commands generated directly from Swagger — always in sync
Inconsistent parameter validation Strict validation at build time via source generation
Unparseable output for automation Every response wrapped in a predictable JSON envelope
Manual DTO maintenance Zero hand-written DTOs — all generated from swagger.json
$ awork users list --page-size 3

{
  "statusCode": 200,
  "traceId": "abc123",
  "response": [...]
}

Installation

Homebrew (macOS/Linux)

brew tap awork-io/awork-cli
brew install awork-cli

Download binary

Grab the latest release for your platform from GitHub Releases.

Platform Binary
macOS (Apple Silicon) awork-osx-arm64.tar.gz
macOS (Intel) awork-osx-x64.tar.gz
Linux (x64) awork-linux-x64.tar.gz
Windows (x64) awork-win-x64.zip

Quick Start

1. Set your token (fastest path)

echo "AWORK_TOKEN=your-token-here" > .env

2. Or login with OAuth (DCR)

awork auth login

3. Verify setup

awork doctor

4. Explore

awork --help

Authentication

API Token

Set your awork API token via environment variable or .env file:

export AWORK_TOKEN=your-token-here
# or
echo "AWORK_TOKEN=your-token-here" > .env

Use --env <PATH> to load a different .env file.

OAuth (Dynamic Client Registration)

awork auth login

This opens a browser and stores an OAuth token + refresh token in the user config file. If your tenant requires DCR authorization, provide a token via AWORK_DCR_TOKEN. Override OAuth settings with --redirect-uri, --scopes, or env vars: AWORK_OAUTH_REDIRECT_URI, AWORK_OAUTH_SCOPES, AWORK_OAUTH_CLIENT_ID.

Auth Precedence

Default: API token wins. Override with:

awork --auth-mode oauth users list

Valid modes: auto (default), token, oauth. Environment variable: AWK_AUTH_MODE or AWORK_AUTH_MODE.

Config File

User config is stored at:

  • macOS/Linux: ~/.config/awork-cli/config.json
  • Windows: %APPDATA%\\awork-cli\\config.json

Override with:

awork --config /path/to/config.json auth status

Usage

Command Structure

Commands follow a consistent pattern derived from the Swagger spec:

awork <domain> [resource] <action> [positional-args] [--options]
  • Domains are top-level buckets: users, tasks, projects, times, workspace, ...
  • Resources appear as sub-branches when needed (e.g. users invitations, tasks tags)
  • Actions use predictable verbs: list, get, create, update, delete
  • Positional args match path parameters in URL order
  • Options are kebab-case query/body parameters

Discover Commands

# List all resource groups
awork --help

# List actions for a domain
awork users --help

# Get help for a specific command
awork users list --help

Auth Commands

# OAuth login
awork auth login

# Save API token
awork auth login --token "$AWORK_TOKEN"

# Status
awork auth status

# Logout (clear tokens)
awork auth logout

Global Options

These options are available on all API commands:

Option Description
--select <FIELDS> Filter response fields (client-side). Example: --select "id,name,createdOn"
--output <FORMAT> Output format: json (default) or table
--page <N> Page number for paginated endpoints (default: 1)
--page-size <N> Items per page for paginated endpoints
--env <PATH> Load environment variables from a custom .env file
--token <TOKEN> Override the API token for this request
--auth-mode <MODE> Force auth mode: auto, token, or oauth
--config <PATH> Use a custom config file path

Examples

Basic Operations

# List users
awork users list

# List with pagination and field selection
awork users list --page-size 5 --select "id,firstName,lastName"

# Table output for quick inspection
awork users list --output table --select "firstName,lastName"

# Get user by ID (positional path param)
awork users get 550e8400-e29b-41d4-a716-446655440000

# Get tasks/projects by UUID or human-readable key
awork tasks get BUG-1
awork projects get BUG

# Search with filters
awork search get-search \
  --search-term "agent" \
  --search-types "user" \
  --top 3 \
  --include-closed-and-stuck true

Creating Resources

# Create with inline params
awork tasks create \
  --name "Welcome" \
  --base-type private \
  --entity-id 550e8400-e29b-41d4-a716-446655440000

# Create from JSON file
awork tasks create --body @samples/private-task.json

# Merge file + overrides
awork tasks create \
  --body @payload.json \
  --set name="Override Title"

Advanced Body Construction

# Inline JSON arrays with --set-json
awork workspace absence-regions users-assign \
  --set regionId=550e8400-e29b-41d4-a716-446655440000 \
  --set-json userIds='["user-1","user-2"]'

# JSON arrays from file
awork workspace absence-regions users-assign \
  --set regionId=550e8400-e29b-41d4-a716-446655440000 \
  --set-json userIds=@/tmp/users.json

# Nested properties
awork task-tags tasks-update-tags \
  --set newTag.name=Priority

Piping with jq

The consistent JSON envelope makes jq integration seamless:

# Get first user's ID
awork users list --page-size 1 | jq -r '.response[0].id'

# List project names only
awork projects list | jq -r '.response[].name'

# Get task count by status
awork tasks list | jq '.response | group_by(.taskStatusId) | map({status: .[0].taskStatusId, count: length})'

# Chain commands: create task for first active user
USER_ID=$(awork users list --page-size 1 | jq -r '.response[0].id')
awork tasks create --name "Welcome" --base-type private --entity-id "$USER_ID"

# Check if request succeeded
awork users me | jq -e '.statusCode == 200' > /dev/null && echo "OK" || echo "Failed"

Deep Links

Build web links for awork app routes:

# Known entity type and ID/key
awork links get task <task-key-or-id>
awork links get project <project-key-or-id>
awork links get user <user-id>
awork links get company <company-id>
awork links get document <document-id>
awork links get time-report <report-id>
awork links get task-view <view-id>

# Task-scoped links
awork links get comment <comment-id> --task <task-key-or-id>
awork links get task-list <task-list-id> --project <project-key-or-id>

# Static app destinations
awork links get dashboard
awork links get account-settings
awork links get planner
awork links get whats-new

# Resolve a task key or probe a UUID across supported entity types
awork links resolve NIKE-42
awork links resolve <entity-id>

Links use https://app.awork.com as the app base URL.

Real-World Workflow: Onboard a New Team Member

Step 1 — Invite the user (skip email for programmatic flow)

# samples/invite.json
{
  "workspaceId": "<workspace-id>",
  "email": "new.user@example.com",
  "firstName": "New",
  "lastName": "User",
  "title": "Engineer",
  "position": "Platform",
  "roleId": "<role-id>",
  "teamIds": ["<team-id>"],
  "skipSendingEmail": true
}
awork invitations create --body @samples/invite.json

Step 2 — Accept the invitation programmatically

# samples/accept.json
{ "invitationCode": "<invitation-code>" }
awork invitations accept --body @samples/accept.json

Step 3 — Create a welcome task for the new user

# samples/private-task.json
{
  "name": "Welcome to awork",
  "description": "Start here",
  "baseType": "private",
  "entityId": "<user-id>",
  "isPrio": true,
  "plannedDuration": 1800
}
awork tasks create --body @samples/private-task.json

Or inline with overrides:

awork tasks create \
  --body @samples/private-task.json \
  --set entityId="$(awork users list | jq -r '.response[0].id')"

Output Contract

Every command returns a consistent JSON envelope:

{
  "statusCode": 200,
  "traceId": "00-abc123...",
  "response": { ... }
}
Field Description
statusCode HTTP status code from the API
traceId Correlation ID from response headers (best effort)
response Parsed JSON body, or raw text if not JSON

This makes awork trivial to integrate with jq, scripts, and AI agents.


Development

Building from Source

git clone https://github.com/awork-io/awork-cli.git
cd awork-cli
dotnet build
dotnet run --project src/Awk.Cli -- --help

Build Release Binary

# macOS Apple Silicon
dotnet publish src/Awk.Cli -c Release -r osx-arm64

# macOS Intel
dotnet publish src/Awk.Cli -c Release -r osx-x64

# Linux
dotnet publish src/Awk.Cli -c Release -r linux-x64

# Windows
dotnet publish src/Awk.Cli -c Release -r win-x64

Output: src/Awk.Cli/bin/Release/net10.0/<rid>/publish/awork

Run Tests

# All tests
dotnet test

# Individual test suites
./scripts/test-build.sh       # Build verification
./scripts/test-cli-names.sh   # Command naming consistency
./scripts/test-example.sh     # Example command validation
./scripts/test-params.sh      # Parameter handling
./scripts/test-auth.sh        # Auth flows (token)
./scripts/test-unit.sh        # Unit tests

Refresh Swagger

The CLI generator reads the checked-in swagger.json. To pick up API changes from the awork app, refresh that file first:

./scripts/update-swagger.sh
dotnet build

By default the script reads ../app/backend/services/ai-service/service/Assets/AworkOpenApiV1.json. Set AWORK_OPENAPI_SOURCE=/path/to/AworkOpenApiV1.json to use another file. Set API_BASE_URL=https://app.cwork.io to fetch the live docs endpoint instead, matching the app repo's API client generation flow.

Package the Source Generator

dotnet pack src/Awk.CodeGen -c Release

Output: src/Awk.CodeGen/bin/Release/Awk.CodeGen.*.nupkg

Create a Release

Every push to main runs the release workflow. Push-triggered releases use an automatic version based on the GitHub Actions run number, for example 0.2.1234. The same version is stamped into the binary, so awork --version matches the GitHub release.

You can also run the release workflow manually when you need an explicit version:

gh workflow run release.yml \
  -f version=0.2.0 \
  -f prerelease=false

This will:

  1. Build binaries for macOS (ARM64/x64), Linux, and Windows
  2. Create a GitHub release with all artifacts
  3. Update the Homebrew formula (requires HOMEBREW_TAP_TOKEN secret)

Architecture

┌─────────────────────────────────────────────────────────────┐
│                        swagger.json                         │
└─────────────────────────┬───────────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────────────┐
│                    Awk.CodeGen                              │
│              (Roslyn Source Generator)                      │
│                                                             │
│   • Parses OpenAPI 3.0 spec                                 │
│   • Emits DTOs to Awk.Generated namespace                   │
│   • Generates typed API client methods                      │
│   • Creates CLI commands grouped by Swagger tags            │
└─────────────────────────┬───────────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────────────┐
│                       Awk.Cli                               │
│                  (Spectre.Console.Cli)                      │
│                                                             │
│   • Token + OAuth authentication (DCR)                      │
│   • Parameter validation                                    │
│   • JSON envelope output                                    │
└─────────────────────────────────────────────────────────────┘

Rebuilding regenerates the CLI from the current swagger.json; it does not fetch a newer app spec by itself. Refresh swagger.json first when the app OpenAPI contract changes. No manual DTO updates are required.


Project Structure

awork-cli/
├── .github/
│   └── workflows/
│       ├── ci.yml            # Build & test on PRs
│       └── release.yml       # Multi-platform release on tags
├── src/
│   ├── Awk.CodeGen/          # Source generator (NuGet-packageable)
│   └── Awk.Cli/              # CLI application
├── tests/
│   ├── Awk.CodeGen.Tests/    # Generator unit tests
│   └── Awk.Cli.Tests/        # CLI integration tests
├── homebrew/                 # Homebrew formula template
├── scripts/                  # Test and Swagger helpers
├── samples/                  # Example JSON payloads
└── swagger.json              # awork OpenAPI spec

AI Agent Setup

The awork CLI ships with a built-in skill command that exports a ready-made skill definition for AI coding agents. This lets agents understand available commands, authentication, and output formats without manual configuration.

Claude Code

Register the awork CLI skill globally so it's available across all your projects:

mkdir -p ~/.claude/skills/awork-cli
awork skill > ~/.claude/skills/awork-cli/SKILL.md

After this, Claude Code will automatically pick up the skill and can use the awork CLI on your behalf.


License

MIT


Built with Spectre.Console • Powered by Roslyn Source Generators

About

awork CLI to interact with awork, generated from the OpenAPI specification.

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages