- Do not run build commands automatically for verification.
- When finishing work, state that the task is complete and ask the user to verify it manually.
- In plugin id descriptions, declare each id only once at one level. If a model plugin merges a resources plugin, resource ids must stay in the resources plugin and must not be redeclared in the model plugin.
TypeScript/Svelte 4 monorepo using Rush.js (pnpm 10.15.1), Node >=20 <25, Webpack 5, Electron, Jest.
Respond to user using Russian language, all comments should be in English.
- Do not add
:globalstyles in feature components to override other components' internals. Keep styles scoped to the owning component. Fix shared layout or printing issues in the responsible shared component (for example, Scroller), rather than adding feature-specific overrides.
TypeScript: Strict types, interfaces over types, avoid any, export types separately
- Type object literals through variable annotations (
const value: T = { ... }), including in tests. For incomplete mocks, useconst mock: Partial<T> = { ... }orPick<T, K>and apply any necessaryas Tonly to the variable at its use site. Do not assert types directly on object literals ({ ... } as T), including throughas unknown as T, or disable@typescript-eslint/consistent-type-assertionsto bypass this rule. Svelte: Script/style/markup order, reactive$:, stores for state, small focused components Naming: Fileskebab-case, ComponentsPascalCase, functionscamelCase, constantsUPPER_SNAKE_CASE
models/*- Shared types/models- If add resources like component: '' as AnyComponent, ensure is it added into one of api package/resources package or model package. It should be defined only once. It could be IntlString as well or any other '' as Ref declaration.
server-*- Server packagesplugins/*- Client pluginspackages/*- Reusable utilities- Projects 2-3 levels deep, each with
package.json
- Before adding or changing traces, metrics, structured logging, context propagation, or observability backends, read Observability with MeasureContext. Application instrumentation uses
MeasureContext; OpenTelemetry instruments and SDK calls belong insidemeasurements-otlp. Update the guide when changing the context contract or backend behavior. - Changes to
MeasureContext, its shared lifecycle, metric recording, proxies, or backend implementations require the contract and performance checks. Report timing and retained-memory results, including failures or checks that could not run; passing functional tests alone is insufficient.
- Before creating UI, check the
@hcengineering/uicomponent catalog, public exports, and existing usages. Prefer importing from@hcengineering/uiand extending or composing existing components; do not use deep imports or create near-duplicates. - If no suitable component exists, add it to
packages/uiwhen it is a reusable UI primitive or serves multiple features. Keep domain-specific components with their owning feature and follow existing theming, localization, and accessibility patterns. - Export every new public component from
packages/ui/src/index.tsand add it to one primary category in the component catalog.
- Use the utility classes in
packages/theme/styles/_layouts.scssand theme tokens (--spacing-*,--theme-*) before writing component CSS; keep a<style>block only for what has no class. - Reuse existing
IntlStringids and strings before adding one, and name a key after its text. A new key goes to every supported locale. - Do not add
aria-*orroleby default. Label icons throughtooltipandLabel, and mark decorative<svg>without textaria-hidden="true". - In Playwright tests select by
data-id, notdata-testid.
rush install # Install deps
rush build # Build all
rush build --to PKG # Build specific
rush add -p PKG # Add dependencyIMPORTANT: After making changes to service code (in services/, pods/, etc.), you must rebuild Docker images:
Note: If you're running the UI via rush dev (dev-server), you don't need to restart the front Docker container. Changes will be picked up automatically by the dev server.
# Build Docker images for specific service
rush docker:build --to @hcengineering/pod-ai-bot
rush docker:build --to @hcengineering/love-agent
# Restart Docker containers to use new images
docker compose -f dev/docker-compose.yaml restart aibot
docker compose -f dev/docker-compose.yaml restart love-agentWorkflow for service changes:
- Make code changes to service
- Run
rush build --to <package>(builds TypeScript) - Never Run
rushx formatin the package directory (format & lint) - MAY CAUSE FILE CORRUPTIONS. Lets user do it. - Run
diagnosticsto check for errors - Run
rush docker:build --to <package>(builds Docker image) - Restart the Docker container
Example for ai-bot service:
# After editing services/ai-bot/pod-ai-bot/src/workspace/love.ts
cd services/ai-bot/pod-ai-bot
diagnostics path: "services/ai-bot/pod-ai-bot/src/workspace/love.ts"
cd ../../..
rush docker:build --to @hcengineering/pod-ai-bot
docker compose -f dev/docker-compose.yaml restart aibotIMPORTANT: Use diagnostics tool to check for TypeScript/Svelte errors, NOT rush build:
- ✅
diagnostics()- Check all files for errors/warnings (fast, uses language server) - ✅
diagnostics({ path: "plugins/tracker-resources/src/utils.ts" })- Check specific file - ❌
rush build- Don't use for error checking (runs full transpilation, slower)
rush build performs transpilation which may succeed even with type errors. Always use diagnostics to verify code correctness.
After making changes, always validate the affected packages to ensure diagnostics are accurate:
# Navigate to each modified package and run:
cd <modified-package-directory>
rushx build
rushx _phase:validate
# Examples:
cd plugins/love-resources
rushx build
rushx _phase:validate
cd models/love
rushx build
rushx _phase:validate
cd server-plugins/love-resources
rushx build
rushx _phase:validateThis ensures that the language server has the correct build artifacts and validation passes for the specific packages you modified.
AI AGENTS: DO NOT run formatting commands automatically. Formatting can corrupt or erase files. Let the user handle formatting.
This ensures code style consistency and catches linting errors before commit.
NEVER run formatting commands in parallel or concurrently. The formatter can corrupt or completely erase file contents when run simultaneously on multiple packages.
Rules:
- ❌ DO NOT run
rushx formatcommands - ❌ DO NOT use
--forceflag with formatting - it can cause content loss - ✅ DO run formatting sequentially, one package at a time
- ✅ DO verify file contents after formatting with
git difforgit status - ✅ DO restore files immediately with
git checkout -- <file>if content is lost
If you see files becoming empty or losing content after formatting, immediately restore them:
git checkout -- <affected-files>When generating changelogs (the "All commits" lists), follow these rules:
- Exclude commits whose subject contains
Merge remote-tracking(filter them out). - Strip
Signed-off-by:footers from commit messages (remove the footer content and any lines that are onlySigned-off-by:). - Recommended pipeline (example):
git log --pretty=format:'- %h %s' <range> | grep -v -F 'Merge remote-tracking' | sed -E 's/\s*Signed-off-by:.*$//'- Note:
git log --no-mergesremoves all merge commits; use it only if you intentionally want to omit all merges.
Apply these filters when updating changelog.md or generating release notes so the generated logs exclude noisy merge-tracking commits and signed-off-by lines.
- When generating process definitions or templates, if required functionality appears to be missing or its support is not confirmed, stop generation and tell the user exactly what is missing and which process behavior depends on it. Do not invent actions, triggers, transforms, ids, parameters, DSL syntax, or implicit engine behavior. Do not silently substitute a workaround or extend the engine; wait for the user's direction. This rule applies only to process generation, not to general development work.
- Before explaining or designing card types and processes, read Card types and process authoring. It is the first reference for document structure, supported operation parameters, execution rules, context expressions, and import formats. Use its documented contracts and examples without searching the codebase for each routine task.
- YAML is the chosen authoring DSL. Both card modules with embedded processes and standalone process templates use one format (
version: 2) alongside native JSON. Read its contract in the authoring guide; version 1 is unsupported. Use named processes with nested states/transitions/actions, short built-in operation names and model sections; graph ownership and ranks are generated, and import resolves storage identities. YAML block order defines branch priority. Exports retain every native operation/property and include a catalog generated from installed methods, triggers and functions; standalone exports use readable graph references and support all native slot kinds. Use that catalog and the guide as the first authoring reference. Do not turn ordinary YAML authoring back into native JSON document lists. The UI YAML editor validates drafts, creates new definitions, and can save into a selected existing process; active executions are not migrated or inspected. - Reuse the existing YAML format or import infrastructure where it naturally fits the new DSL. Compatibility is optional: do not distort the new format or add adapters solely to force reuse when the existing design does not fit.
- Prefer small, named logical blocks with one clear responsibility when designing processes. Make each block's inputs, outputs, waiting condition, and outgoing transitions explicit. Use states and cohesive transitions for these blocks; do not imply new runtime block or subprocess behavior.
- In v2 YAML, publish ordinary method outputs with
as: nameand use$context.namefor their values; the compiler generates context wiring from the installed method model or an offline catalog. Use$slots.namefor a binding identity and$card.namefor a card field value. Never guess this distinction from parameter names or invent missing output contracts. Keep unusual native context/result metadata explicit when it cannot be reproduced by shorthand. - Declare ordinary typed values in named action
resultsmaps and useexprwithfrom/call,reduce,pipeand literalfallbackfor registered native functions. Short types work in fields, slots and results; an attribute slot only needs its type. Use the v2 schema for structural tooling and the guide for execution semantics. Results do not imply method support, task aggregation or availability before their producer completes. Keep the detailed implementation plan in authoring-plan.md. - Keep documentation, generated files, example labels, enum values, and descriptions in English.
- For a workspace-specific process, use its exported process or card module and resolve its field/relationship bindings. Repository source describes the engine and available operations; it does not contain every workspace's configured processes.
- Present the card fields, state graph, transitions with ordered actions, context dependencies, and required bindings before generating a process template. Follow the existing process or module import format.
- Platform
DocumentQuerydoes not support$or. Do not use it infindAll,findOne, live queries, or selector filters. - Always handle errors (proper Error subclasses, catch promises)
- Use async/await, Promise.all() for parallel ops
- Svelte stores for shared state, separate business logic
- JSDoc public APIs, tests alongside code
- Check with
diagnosticsbefore making changes; do not commit locally — use diffs for review and let maintainers handle commits
When debugging issues:
- Add comprehensive logging first - use
console.logwith structured objects showing state, parameters, IDs - Test and analyze logs - let user run the app and provide actual console output
- Propose options before applying fixes or workarounds - when you identify multiple possible approaches (including quick or temporary workarounds), outline each option clearly (pros, cons, risks, and how invasive the change is) and ask the user which variant to proceed with. Do not implement non-trivial temporary workarounds without explicit approval.
- Identify root cause from logs - trace the flow, compare expected vs actual values
- Fix the issue based on findings
- Remove all logging after fix is confirmed - keep production code clean
Logging format:
console.log('[ComponentName.methodName] Description', {
key1: value1,
key2: value2,
objectId: object?._id // Use optional chaining for safety
})❌ any without reason
❌ console.log() in production
❌ Mixed concerns
❌ Circular deps
❌ Ignoring TS errors
❌ Using rush build to check for errors
❌ Running formatting in parallel (causes content loss!)
❌ Using --force flag with formatter
❌ Git policy: do NOT make commits, resets, reverts, or switch branches. Use git only for read-only operations (diff, status, log).
- Infer location from context (models/server/plugins/packages)
- Match existing patterns in codebase
- Include proper imports/types
- When adding a new
IntlStringkey, add corresponding entries to the component language files undercomponent-assets/langfor every supported locale (at minimum include the English entry) and update translations as needed; ensure you rundiagnostics(). Do not commit changes locally — prepare a diff for review and let maintainers perform commits. !!! If diagnostics are not disappearing for fixed items, stop and inform user to reload language servers or wait for build. Wait for continue request from user. - Add error handling
- Use existing utils first
- When fixing bugs:
- Read existing code thoroughly before changing
- Use logging to understand actual runtime behavior
- Trace data flow through components
- Verify assumptions with logs before implementing fixes
- Remove debug code when done
The app uses a provider-based selection/focus system:
focusStore- global focus stateselectionStore- global selection stateListSelectionProvider- manages list navigation, delegates to view-specific handlersSelectDirection-'vertical'(up/down) or'horizontal'(left/right in tables, first/last in lists)
Key principles:
- Navigation uses actual displayed order (from
getLimited()) not projection order - Focus changes propagate through
updateFocus() - Selection follows focus via provider delegation
- Scroll happens automatically via
scrollIntoView()on navigation
- Use EPL 2.0 for all new and modified source files.
- For new files, use
Copyright © <year> TraceX SAS. - Preserve all existing copyright and license notices.
- When materially modifying an existing EPL file, add the TraceX SAS copyright line without removing the original copyright lines.
Use the following header, adapting only the comment syntax to the file type:
//
// Copyright © <year> TraceX SAS.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.