Skip to main content Set up a local development loop for MaintainX integration development.
Use when configuring dev environment, testing API calls locally,
or setting up a sandbox workflow for MaintainX.
Trigger with phrases like "maintainx dev setup", "maintainx local",
"maintainx development environment", "maintainx testing setup".
npx skills add jeremylongshore/claude-code-plugins-plus-skills --skill maintainx-local-dev-loop ai automation claude-code devops mcp ai-agents
MaintainX Local Dev Loop
Overview
Set up an efficient local development workflow for building and testing MaintainX integrations with hot reload, mock servers, and automated testing.
Prerequisites
Completed maintainx-install-auth setup
Node.js 18+ installed
MAINTAINX_API_KEY environment variable set
Instructions
Step 1: Initialize TypeScript Project
mkdir maintainx-integration && cd maintainx-integration
npm init -y
npm install axios dotenv
npm install -D typescript tsx vitest @types/node
npx tsc --init --target ES2022 --module NodeNext --moduleResolution nodenext --outDir dist
Create tsconfig.json paths:
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "nodenext",
"outDir": "dist",
"strict": true,
"esModuleInterop": true
},
"include": ["src/**/*"]
}
Step 2: Project Structure maintainx-integration/
├── src/
│ ├── client.ts # MaintainX API client (from install-auth)
│ ├── work-orders.ts # Work order service layer
│ └── sync.ts # Data sync logic
├── tests/
│ ├── client.test.ts # Unit tests with mocks
│ └── integration.test.ts # Live API tests
├── .env # MAINTAINX_API_KEY=...
├── .env.example # MAINTAINX_API_KEY=your-key-here
├── package.json
└── tsconfig.json
Step 3: Dev Scripts in package.json {
"scripts": {
"dev": "tsx watch src/index.ts",
"test": "vitest run",
"test:watch": "vitest",
"test:integration": "INTEGRATION=true vitest run tests/integration.test.ts",
"build": "tsc",
"repl": "tsx src/repl.ts"
}
}
Step 4: Write Unit Tests with Mocked API // tests/client.test.ts
import { describe, it, expect, vi, beforeEach } from 'vitest';
import axios from 'axios';
vi.mock('axios');
describe('MaintainXClient', () => {
beforeEach(() => {
vi.resetAllMocks();
process.env.MAINTAINX_API_KEY = 'test-key-123';
});
it('creates a work order', async () => {
const mockResponse = {
data: { id: 1, title: 'Test WO', status: 'OPEN' },
};
vi.mocked(axios.create).mockReturnValue({
post: vi.fn().mockResolvedValue(mockResponse),
interceptors: { response: { use: vi.fn() } },
} as any);
const { MaintainXClient } = await import('../src/client');
const client = new MaintainXClient();
const result = await client.createWorkOrder({ title: 'Test WO' });
expect(result.data.title).toBe('Test WO');
expect(result.data.status).toBe('OPEN');
});
it('paginates work orders', async () => {
const page1 = { data: { workOrders: [{ id: 1 }], cursor: 'abc' } };
const page2 = { data: { workOrders: [{ id: 2 }], cursor: null } };
const getMock = vi.fn()
.mockResolvedValueOnce(page1)
.mockResolvedValueOnce(page2);
vi.mocked(axios.create).mockReturnValue({
get: getMock,
interceptors: { response: { use: vi.fn() } },
} as any);
const { MaintainXClient } = await import('../src/client');
const client = new MaintainXClient();
const all = [];
let cursor: string | undefined;
do {
const { data } = await client.getWorkOrders({ cursor });
all.push(...data.workOrders);
cursor = data.cursor;
} while (cursor);
expect(all).toHaveLength(2);
});
});
Step 5: Interactive REPL // src/repl.ts
import * as repl from 'node:repl';
import 'dotenv/config';
import { MaintainXClient } from './client';
const client = new MaintainXClient();
console.log('MaintainX REPL ready. `client` is available.');
console.log('Try: await client.getWorkOrders({ limit: 3 })');
const r = repl.start({ prompt: 'maintainx> ' });
r.context.client = client;
# Start REPL
npm run repl
# maintainx> const { data } = await client.getWorkOrders({ limit: 3 })
# maintainx> data.workOrders.map(wo => wo.title)
Output
TypeScript project configured with tsx watch for hot reload
Vitest unit tests with mocked MaintainX API responses
Interactive REPL for exploring the API
.env.example template for team onboarding
Dev/test/build scripts in package.json
Error Handling Issue Solution MAINTAINX_API_KEY undefinedCopy .env.example to .env and fill in your key 429 Rate Limited during dev Add delays between calls, use mocks for unit tests TypeScript import errors Ensure moduleResolution: "nodenext" in tsconfig tsx not foundInstall with npm i -D tsx
Resources
Next Steps For SDK patterns and best practices, see maintainx-sdk-patterns.
Examples Docker-based dev environment :
# Dockerfile.dev
FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD ["npm", "run", "dev"]
# docker-compose.dev.yml
services:
app:
build: { dockerfile: Dockerfile.dev }
env_file: .env
volumes: ["./src:/app/src"]
Run integration tests against live API :
INTEGRATION=true npm run test:integration
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Set up and use 1Password CLI (op). Use when installing the CLI, enabling desktop app integration, signing in (single or multi-account), or reading/injecting/running secrets via op.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Set up and use 1Password CLI (op). Use when installing the CLI, enabling desktop app integration, signing in (single or multi-account), or reading/injecting/running secrets via op.