Skip to content

feat!: complete architecture redesign with GraphQL codegen, auth system, and developer tooling#45

Merged
iamfj merged 177 commits into
linearis-oss:nextfrom
iamfj:v2
Feb 13, 2026
Merged

feat!: complete architecture redesign with GraphQL codegen, auth system, and developer tooling#45
iamfj merged 177 commits into
linearis-oss:nextfrom
iamfj:v2

Conversation

@iamfj
Copy link
Copy Markdown
Member

@iamfj iamfj commented Feb 13, 2026

Overview

Hey Carlo! 👋

This is a comprehensive contribution from my fork that redesigns the Linearis architecture from the ground up. The goal was to make the codebase more maintainable, type-safe, and extensible — while also adding several new features that the community has been requesting.

This PR represents ~18 merged PRs in my fork, covering architecture, features, tooling, and documentation. I've organized everything below so you can review it incrementally.

Stats: 189 files changed, ~21k insertions, ~38k deletions (net reduction of ~17k lines)


What Changed and Why

1. GraphQL Codegen Migration

PRs: #2, #3, #4, #5, #6, #7, #8

Why: The original codebase used manually maintained TypeScript type definitions and runtime GraphQL string loading. This was error-prone, hard to keep in sync with the Linear API schema, and lacked compile-time type safety.

What:

  • Set up graphql-codegen infrastructure with a codegen.config.ts
  • Migrated all queries and mutations to .graphql files under graphql/queries/ and graphql/mutations/
  • Replaced all manual type definitions (linear-types.d.ts) with auto-generated types
  • Every client.request<T>() call is now fully typed with codegen output
  • Removed the old src/queries/ runtime loader and manual types

2. Five-Layer Architecture Redesign

PR: #10

Why: The original utils/ directory mixed concerns — ID resolution, GraphQL operations, business logic, and CLI orchestration were all tangled together. This made it hard to test individual layers, reuse logic, or reason about data flow.

What: Introduced a strict five-layer architecture:

Layer Directory Responsibility Client
Client src/client/ API wrappers
Resolver src/resolvers/ Human ID → UUID LinearSdkClient
Service src/services/ Business logic & CRUD GraphQLClient
Command src/commands/ CLI orchestration Both via createContext()
Common src/common/ Shared utilities

Key design decisions:

  • ID resolution happens exactly once in the resolver layer — services only accept UUIDs
  • Strict client separation: resolvers use the SDK client, services use the GraphQL client
  • Commands are thin orchestrators — no business logic, just wire up resolvers → services → output
  • Created typed GraphQLClient and LinearSdkClient wrappers
  • Added shared error types (notFoundError, multipleMatchesError)
  • Comprehensive unit tests for every resolver and service with one-layer-deep mocking

3. CLI Naming Redesign & Two-Tier Usage System

PRs: #12, #14

Why: Since Linearis is designed for LLM agents, the usage/help system needs to be token-efficient. Traditional --help output is verbose and wastes tokens. Also, some command names were inconsistent (e.g., project-milestones vs milestones, embeds vs files).

What:

  • Renamed commands for consistency: project-milestonesmilestones, embedsfiles
  • Standardized option names across all commands
  • Built a two-tier usage system optimized for LLM token consumption:
    • Tier 1 (linearis usage): ~200 token overview of all domains
    • Tier 2 (linearis <domain> usage): ~300-500 token detailed reference per domain
  • Every command exports DomainMeta with structured metadata
  • USAGE.md is auto-generated on every build and shipped with the package

4. Authentication System

PR: #26

Why: The original auth only supported env vars and a plaintext token file. There was no interactive setup, no token validation, and no secure storage — making it hard for new users to get started.

What: Full linearis auth command group:

  • linearis auth login — interactive token setup with browser-based token page, encrypted local storage
  • linearis auth status — shows current auth method and token source
  • linearis auth logout — removes stored credentials
  • AES-256-GCM encrypted token storage at ~/.linearis/token
  • Token validation via GetViewer GraphQL query
  • Structured auth error detection and output
  • Backwards-compatible with existing env var and legacy plaintext file
  • Comprehensive unit tests for all auth flows

5. Issue Relations Support

PR: #30 — addresses czottmann/linearis#27

Why: Community-requested feature for managing issue dependencies and relationships.

What:

  • New issue-relation-service with create, find, and delete operations
  • GraphQL mutations for issue relations
  • Relation flags on both issues create and issues update:
    linearis issues create "Task" --team ENG --blocks ENG-124
    linearis issues update ENG-123 --related ENG-200
    linearis issues update ENG-123 --duplicate ENG-50
  • Supports: --blocks, --blocked-by, --related, --duplicate
  • Unit tests for all relation operations

6. Developer Tooling

PRs: #29, #23, #9

What:

  • Biome for formatting and linting (replaces ad-hoc style)
  • Lefthook for git hooks (format + lint on pre-commit)
  • Commitlint for conventional commit enforcement
  • Updated CI workflow for clarity and structure
  • Added Claude code review and PR assistant workflows

7. Codebase Simplification

PR: #31

What: Final cleanup pass removing verbose JSDoc comments that restated what the code expressed, simplifying expressions, and removing unused interfaces. Net result: -634 lines with no behavioral changes.

8. Agent Instructions & Skills

PRs: #27, #28

What:

  • Comprehensive AGENTS.md (also serves as CLAUDE.md) documenting all architectural rules, patterns, and anti-patterns for AI-assisted development
  • 15 Claude Code agent skills for structured workflows (TDD, debugging, code review, PR creation, etc.)

Breaking Changes

  • Command renames: project-milestonesmilestones, embedsfiles
  • Option renames: Standardized across all commands (e.g., --issues-first--limit)
  • search subcommands merged into list with filter flags
  • Architecture: Complete reorganization of source files (relevant for contributors)

Upstream Issues Addressed

How to Review

I'd suggest reviewing in this order:

  1. Architecture overview: Read the updated AGENTS.md for the full picture
  2. GraphQL layer: graphql/ directory and codegen.config.ts
  3. Client layer: src/client/
  4. Common layer: src/common/
  5. Resolvers + Services: src/resolvers/ and src/services/
  6. Commands: src/commands/
  7. Tests: tests/unit/
  8. Auth system: src/commands/auth.ts, src/common/encryption.ts, src/common/token-storage.ts

All Fork PRs (chronological)

# PR Description
1 #2 Setup GraphQL codegen infrastructure
2 #3 Migrate GraphQL queries to separate files
3 #4 Migrate issues service to codegen types
4 #5 Fix command parameter types for codegen
5 #6 Migrate documents and attachments to codegen
6 #7 Migrate cycles and milestones to codegen
7 #8 Remove manual types, finalize codegen migration
8 #9 Add Claude Code GitHub workflow
9 #10 Five-layer architecture redesign
10 #12 CLI naming redesign + two-tier usage system
11 #14 Remove obsolete src/queries loaders
12 #23 Update CI workflow
13 #26 Authentication system with encrypted storage
14 #27 Claude Code agent skills
15 #28 AGENTS.md documentation
16 #29 Biome, lefthook, and commitlint tooling
17 #30 Issue relations support
18 #31 Codebase simplification

Happy to discuss any of this, break things into smaller pieces if preferred, or adjust the approach. Looking forward to your feedback! 🙏

iamfj and others added 30 commits February 4, 2026 10:07
Add GitHub Actions workflow for automated PR assistance using Claude.
This workflow provides intelligent PR reviews and suggestions.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add GitHub Actions workflow for automated code reviews using Claude.
This workflow analyzes code changes and provides detailed feedback.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add concurrency configuration to the Claude code review workflow to manage simultaneous runs and cancel in-progress jobs for pull requests.
Changes GetIssueById and GetIssueByIdentifier to use
CompleteIssueWithCommentsFields fragment instead of CompleteIssueFields,
restoring comment data that was inadvertently removed during the GraphQL
file migration.

This fixes a data regression where reading issues by ID or identifier
would no longer return comment data as expected.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Creates query loader modules in src/queries/ that read GraphQL operations
from .graphql files and export them as string constants. This bridges the
gap between the new .graphql file structure and existing service imports.

The loaders:
- Read .graphql files at runtime using Node.js fs module
- Extract individual operations with fragment dependencies
- Export query/mutation strings with the same names services expect
- Enable existing code to work without modification

Fixes TypeScript compilation errors where services imported from deleted
src/queries/*.ts files. Services now successfully import from the new
loader modules which dynamically load from graphql/queries/ and
graphql/mutations/ directories.

Files added:
- src/queries/issues.ts
- src/queries/documents.ts
- src/queries/attachments.ts
- src/queries/project-milestones.ts

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Updates AGENTS.md (CLAUDE.md) to reflect the new GraphQL architecture:

- Documents the dual structure of graphql/ directory (source .graphql files)
  and src/queries/ (runtime query loaders)
- Updates "Query Definitions" section to explain both components
- Rewrites "Adding GraphQL Queries" workflow to document the new process:
  1. Define operations in .graphql files
  2. Run npm run generate for codegen
  3. Query loaders automatically extract operations
- Changes references from src/queries/common.ts to graphql/queries/issues.graphql
- Explains the separation between human-written .graphql files and
  generated TypeScript types in src/gql/

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add type aliases for GraphQL query/mutation return types to improve
readability in method signatures.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Return raw codegen types directly instead of transforming to manual
types.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Return union type of raw codegen types instead of transforming.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Return raw codegen type directly.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Return raw codegen type directly.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Use QuerySearchIssuesArgs instead of full query type. Remove
transformation.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Delete transformIssueData and doTransformIssueData - no longer needed
since services return raw codegen types.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Line 166 referenced undefined variable 'id' instead of 'input.id'.
This caused a ReferenceError when resolving non-UUID issue identifiers.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Line 572 referenced non-existent 'input.milestoneId' instead of
'input.projectMilestoneId'. This would show 'undefined' in error
messages when milestone resolution fails.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Lines 670-677 spread entire searchArgs object into GraphQL variables,
but SearchIssues query only accepts 'term' and 'first' parameters.
This caused GraphQL validation errors when extra properties like
'limit' were passed through.

Now destructures only 'term' from searchArgs and passes it explicitly
along with 'first' parameter.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Pass QuerySearchIssuesArgs fields directly instead of wrong type.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Ensure parameters match IssueUpdateInput type from codegen.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add type aliases, remove transformations, return raw GraphQL types.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add type aliases, remove transformations, return raw GraphQL types.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Define CycleListOptions and CycleReadOptions locally. Replace
LinearCycle with codegen type alias.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add missing option interfaces (MilestoneListOptions, MilestoneReadOptions,
MilestoneCreateOptions, MilestoneUpdateOptions) and replace
LinearProjectMilestone with ProjectMilestoneUpdateInput from codegen.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Delete linear-types.d.ts - all types now generated from GraphQL
schema via codegen.

- Add type aliases in linear-service.ts for LinearLabel, LinearComment,
  and CreateCommentArgs
- Replace LinearProject with inline type definition
- Fix bug in graphql-issues-service.ts: use input.projectMilestoneId
  instead of input.milestoneId
- Remove dead code for milestone fallback lookup

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
iamfj and others added 19 commits February 10, 2026 00:00
…s with relations

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tring

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Moves resolveIssueId calls for relation targets to before the
createIssue call so invalid target identifiers fail fast without
leaving a partially created issue.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Covers the defensive null check branch on the issue query result.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Deduplicate relation flag logic between issues create and update by
extracting resolveRelationTarget() and applyRelation() helpers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Consolidate duplicated relation flag validation from create and update
handlers into a shared function using the RelationFlags interface.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feat(issues): add issue relations support (blocking/blocked by/related/duplicate)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Consolidates duplicate regex loops in embed-parser, simplifies
URL parsing, and removes redundant documentation comments.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extracts shared SOURCE_LABELS constant in auth, inlines arrow
functions, uses ternary for optional ID resolution, and removes
unused ErrorResponse interface.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
refactor: remove verbose JSDoc and simplify codebase
@iamfj iamfj self-assigned this Feb 13, 2026
@iamfj iamfj merged commit 1cadac5 into linearis-oss:next Feb 13, 2026
2 checks passed
iamfj added a commit that referenced this pull request Apr 7, 2026
Add biome for formatting and linting, lefthook for git hooks, commitlint
for conventional commit enforcement, and editorconfig for IDE consistency.

Set up GraphQL Code Generator to produce TypeScript types from .graphql
definition files. Migrate all queries and mutations from inline TypeScript
strings to dedicated .graphql files under graphql/queries and
graphql/mutations.

Update CI workflow for the new tooling and add codegen, format, and lint
scripts to package.json. Configure prebuild and postinstall hooks to
ensure generated types stay in sync.

Part of #45
iamfj added a commit that referenced this pull request Apr 7, 2026
Replace the flat utils-based structure with a strict five-layer
architecture enforcing separation of concerns:

  CLI Input → Command → Resolver → Service → JSON Output

Clients:
- GraphQLClient: typed wrapper for raw GraphQL operations
- LinearSdkClient: wrapper for Linear SDK access

Common modules:
- context: CommandContext factory with createContext()
- errors: structured error helpers (notFoundError, etc.)
- identifier: UUID detection and identifier parsing
- output: typed outputSuccess/outputError functions
- types: shared type aliases derived from codegen types
- usage: DomainMeta system for self-documenting commands

Resolvers (human ID → UUID, using LinearSdkClient):
- team, project, label, status, issue, cycle, milestone, user

Services (business logic, using GraphQLClient):
- issue, document, attachment, file, comment, cycle, milestone,
  project, team, user, label, issue-relation, auth

Commands rewritten to delegate through layers:
- Rename embeds → files, project-milestones → milestones
- Merge search into list commands
- Add issue relation flags (--blocks, --blocked-by, --relates-to)
- Add cursor pagination (--after, --limit) to all list commands
- Add --assignee resolution by name or email
- Add encrypted token auth (login, status, logout)
- Add usage subcommand to every command group

Remove old utils/, queries/ directories and their tests.
Add comprehensive unit tests for all resolvers and services.

Closes #27, closes #43, closes #47
Refs #2, #3, #14, #16
Part of #45, incorporates #50, #53
iamfj added a commit that referenced this pull request Apr 7, 2026
Rewrite all documentation to reflect the new five-layer architecture,
updated CLI surface, and current development workflows.

- AGENTS.md: restructure for machine-first readability with decision
  trees, anti-patterns, and layer invariants
- README.md: rewrite for current CLI commands and agent optimization
- docs/architecture.md: document five-layer component organization
- docs/development.md: add service/resolver/command templates
- docs/testing.md: add mock patterns per layer
- docs/build-system.md: document codegen pipeline
- docs/files.md: update file catalog for new structure

Remove obsolete files:
- docs/Linear-API@current.graphql (26k-line schema dump)
- docs/plans/ (completed implementation plans)

Part of #45
Refs #54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant