VERIFISDK docsengine v2 · contract 1.5.1 · harness-sdk 1.2.0
Start here

Getting the packages

The SDKs are private packages in a GitHub organisation. Access, tokens, .npmrc and Docker builds — the whole path from no account to a working npm install.


npm install @pragyacyber/harness-sdk does not work out of the box, and it will not tell you why in a useful way. This page is the part that is usually missing.

Two separate things have to be true before an install succeeds:

  1. Your identity has been granted read access to the package. This is a manual decision by someone in the PragyaCyber organisation. There is no self-service path.
  2. You are presenting a token that proves that identity, to the right registry.

Neither implies the other, and the error you get when either is missing is the same one.

Where the packages live

Registryhttps://npm.pkg.github.com (GitHub Packages)
Scope@pragyacyber
OrganisationPragyaCyber on github.com
Visibilityprivate
Packages@pragyacyber/harness-sdk, @pragyacyber/engine-contract

They are not on npmjs.com. An npm install that reaches the public registry and returns 404 Not Found has not failed authentication — it never got as far as GitHub.

Step 1 — get access

Access is granted per consumer, and a person and a repository are different consumers:

For you, as a developer. Your GitHub account needs read access to the package — either as a member of the PragyaCyber organisation with package read, or by being added to the package directly. Ask for it and give your GitHub username.

For a repository's CI. This is the one that surprises people. A GitHub Actions workflow in your repository cannot read a package owned by another repository unless that package has explicitly granted your repository access. The grant is made on the package's own page:

github.com/orgs/PragyaCyber/packages
  → the package
  → Package settings
  → Manage Actions access
  → Add repository
  → select your repository, set the role to Read

It is a manual UI action, once per consuming repository. There is no REST API for it — you cannot script it, and a platform engineer cannot batch it. Give the full owner/repo of every repository that will install the package.

What to send when you ask. Bundle it into one message so it takes one round trip:

GitHub username:        <your-username>
Repositories that will install:
  <owner>/<repo>        (CI: needs Manage Actions access → Read)
  <owner>/<other-repo>
Packages needed:        @pragyacyber/harness-sdk, @pragyacyber/engine-contract
Reason:                 building a <harness | MCP> for <what>

Send it to whoever handed you this documentation — the VERIFI platform team at Pragya Cyber. This site deliberately does not publish a contact address, because the right recipient depends on who is sponsoring your work.

Step 2 — get a token

The registry authenticates with a GitHub token carrying the read:packages scope. You never need write:packages to consume.

If you have the gh CLI — the easy path

gh already holds a token for your account. Add the scope to it:

gh auth refresh -s read:packages

That opens a browser once, then re-issues the CLI's own token with the extra scope. From then on:

export NODE_AUTH_TOKEN=$(gh auth token)

This is the recommended path, and not only for convenience: the value goes straight from gh into a process environment variable. It is never typed, never pasted, and never written to a file where it can be committed.

Without gh — a personal access token

Create one at github.com/settings/tokens with the single scope read:packages, then put it in your environment the same way:

export NODE_AUTH_TOKEN=<paste-it-here-once-then-clear-your-shell-history>

Step 3 — point npm at the registry

Two lines in .npmrc, in your project root:

@pragyacyber:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}

npm expands ${NODE_AUTH_TOKEN} from the environment when it reads the file.

Then install:

npm init -y
npm pkg set type=module
npm i @pragyacyber/harness-sdk@^1.0.0 @pragyacyber/engine-contract@^1.5.0
npm i -D typescript tsx @types/node

Prove the auth works before you write code

npm view @pragyacyber/harness-sdk version

A version number means identity, token and registry routing are all correct, and any later failure is your code. This takes two seconds and saves an afternoon of debugging a build that was never going to resolve.

What you seeWhat it means
a version numberworking — go build something
401 Unauthorizedthe token is missing, unscoped, expired, or fine-grained
404 Not Foundalmost always step 1 — your identity has no read on the package
resolves to npmjs.comthe @pragyacyber:registry line is missing or misspelled

Step 4 — CI

In GitHub Actions, setup-node reads NODE_AUTH_TOKEN for you:

- uses: actions/setup-node@v4
  with:
    node-version: 22
    registry-url: https://npm.pkg.github.com
    scope: '@pragyacyber'
- run: npm ci
  env:
    NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

The built-in secrets.GITHUB_TOKEN works only if your repository was granted read on the package in step 1. Without that grant it authenticates fine and then 404s, which reads like a missing package and is not. If you cannot get the cross-repo grant, fall back to a PAT stored as a repository secret and reference that instead.

Step 5 — Docker builds

A container build needs the token to run npm install, and how you pass it in decides whether you have shipped a credential to everyone who ever pulls the image.

Use a BuildKit secret. It is mounted into a single RUN and never enters a layer:

FROM node:22-slim AS deps
WORKDIR /app

COPY package.json pnpm-lock.yaml ./

# The registry token arrives as a BuildKit SECRET, never an ARG — an ARG is readable
# in the image history, which would bake a credential into every pulled layer.
RUN --mount=type=secret,id=npm_token \
    corepack enable && \
    { echo "@pragyacyber:registry=https://npm.pkg.github.com"; \
      echo "//npm.pkg.github.com/:_authToken=$(cat /run/secrets/npm_token)"; } > .npmrc && \
    pnpm install --prod --frozen-lockfile && \
    rm -f .npmrc

Build it by handing the secret in from the environment:

export NPM_TOKEN=$(gh auth token)
DOCKER_BUILDKIT=1 docker build \
  --secret id=npm_token,env=NPM_TOKEN \
  -t my-harness:dev .

Three details in that RUN are load-bearing:

  • The .npmrc is generated inside the RUN, with the value inline. That is the one place a literal token is acceptable, because this stage is a build stage that is discarded — nothing from it reaches the runtime image. pnpm did not expand the ${NODE_AUTH_TOKEN} form reliably, which is why the value is substituted rather than referenced here.
  • rm -f .npmrc runs in the same RUN. A separate layer would keep the file.
  • The runtime stage copies the checked-in .npmrc — the one with the variable reference — not this one.

In GitHub Actions:

- uses: docker/build-push-action@v6
  with:
    context: .
    secrets: |
      npm_token=${{ secrets.GITHUB_TOKEN }}

Version ranges

npm i @pragyacyber/harness-sdk@^1.0.0 @pragyacyber/engine-contract@^1.5.0

Both packages are at 1.x, and a caret range is the right thing for both.

engine-contract is safe at a caret because the major is additive-only and isCompatible() compares MAJOR only: any 1.x engine understands any 1.x harness. A caret on the contract also means you pick up things like the 1.5.1 Bedrock inference-profile fix without a code change.

Next