diff --git a/tests/secrets/create.test.ts b/tests/secrets/create.test.ts
new file mode 100644
index 00000000..ac880e79
--- /dev/null
+++ b/tests/secrets/create.test.ts
@@ -0,0 +1,88 @@
+import type { VaultName } from 'polykey/dist/vaults/types';
+import path from 'path';
+import fs from 'fs';
+import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
+import PolykeyAgent from 'polykey/dist/PolykeyAgent';
+import { vaultOps } from 'polykey/dist/vaults';
+import * as keysUtils from 'polykey/dist/keys/utils';
+import * as testUtils from '../utils';
+
+describe('commandCreateSecret', () => {
+  const password = 'password';
+  const logger = new Logger('CLI Test', LogLevel.WARN, [new StreamHandler()]);
+  let dataDir: string;
+  let polykeyAgent: PolykeyAgent;
+  let passwordFile: string;
+  let command: Array<string>;
+
+  beforeEach(async () => {
+    dataDir = await fs.promises.mkdtemp(
+      path.join(globalThis.tmpDir, 'polykey-test-'),
+    );
+    passwordFile = path.join(dataDir, 'passwordFile');
+    await fs.promises.writeFile(passwordFile, 'password');
+    polykeyAgent = await PolykeyAgent.createPolykeyAgent({
+      password,
+      options: {
+        nodePath: dataDir,
+        agentServiceHost: '127.0.0.1',
+        clientServiceHost: '127.0.0.1',
+        keys: {
+          passwordOpsLimit: keysUtils.passwordOpsLimits.min,
+          passwordMemLimit: keysUtils.passwordMemLimits.min,
+          strictMemoryLock: false,
+        },
+      },
+      logger: logger,
+    });
+    // Authorize session
+    await testUtils.pkStdio(
+      ['agent', 'unlock', '-np', dataDir, '--password-file', passwordFile],
+      {
+        env: {},
+        cwd: dataDir,
+      },
+    );
+  });
+  afterEach(async () => {
+    await polykeyAgent.stop();
+    await fs.promises.rm(dataDir, {
+      force: true,
+      recursive: true,
+    });
+  });
+
+  test(
+    'should create secrets',
+    async () => {
+      const vaultName = 'Vault1' as VaultName;
+      const vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
+      const secretPath = path.join(dataDir, 'secret');
+      await fs.promises.writeFile(secretPath, 'this is a secret');
+
+      command = [
+        'secrets',
+        'create',
+        '-np',
+        dataDir,
+        secretPath,
+        `${vaultName}:MySecret`,
+      ];
+
+      const result = await testUtils.pkStdio([...command], {
+        env: {},
+        cwd: dataDir,
+      });
+      expect(result.exitCode).toBe(0);
+
+      await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
+        const list = await vaultOps.listSecrets(vault);
+        expect(list.sort()).toStrictEqual(['MySecret']);
+        expect(
+          (await vaultOps.getSecret(vault, 'MySecret')).toString(),
+        ).toStrictEqual('this is a secret');
+      });
+    },
+    globalThis.defaultTimeout * 2,
+  );
+});
diff --git a/tests/secrets/delete.test.ts b/tests/secrets/delete.test.ts
new file mode 100644
index 00000000..9a345167
--- /dev/null
+++ b/tests/secrets/delete.test.ts
@@ -0,0 +1,78 @@
+import type { VaultName } from 'polykey/dist/vaults/types';
+import path from 'path';
+import fs from 'fs';
+import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
+import PolykeyAgent from 'polykey/dist/PolykeyAgent';
+import { vaultOps } from 'polykey/dist/vaults';
+import * as keysUtils from 'polykey/dist/keys/utils';
+import * as testUtils from '../utils';
+
+describe('commandDeleteSecret', () => {
+  const password = 'password';
+  const logger = new Logger('CLI Test', LogLevel.WARN, [new StreamHandler()]);
+  let dataDir: string;
+  let polykeyAgent: PolykeyAgent;
+  let passwordFile: string;
+  let command: Array<string>;
+
+  beforeEach(async () => {
+    dataDir = await fs.promises.mkdtemp(
+      path.join(globalThis.tmpDir, 'polykey-test-'),
+    );
+    passwordFile = path.join(dataDir, 'passwordFile');
+    await fs.promises.writeFile(passwordFile, 'password');
+    polykeyAgent = await PolykeyAgent.createPolykeyAgent({
+      password,
+      options: {
+        nodePath: dataDir,
+        agentServiceHost: '127.0.0.1',
+        clientServiceHost: '127.0.0.1',
+        keys: {
+          passwordOpsLimit: keysUtils.passwordOpsLimits.min,
+          passwordMemLimit: keysUtils.passwordMemLimits.min,
+          strictMemoryLock: false,
+        },
+      },
+      logger: logger,
+    });
+    // Authorize session
+    await testUtils.pkStdio(
+      ['agent', 'unlock', '-np', dataDir, '--password-file', passwordFile],
+      {
+        env: {},
+        cwd: dataDir,
+      },
+    );
+  });
+  afterEach(async () => {
+    await polykeyAgent.stop();
+    await fs.promises.rm(dataDir, {
+      force: true,
+      recursive: true,
+    });
+  });
+
+  test('should delete secrets', async () => {
+    const vaultName = 'Vault2' as VaultName;
+    const vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
+
+    await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
+      await vaultOps.addSecret(vault, 'MySecret', 'this is the secret');
+      const list = await vaultOps.listSecrets(vault);
+      expect(list.sort()).toStrictEqual(['MySecret']);
+    });
+
+    command = ['secrets', 'delete', '-np', dataDir, `${vaultName}:MySecret`];
+
+    const result = await testUtils.pkStdio([...command], {
+      env: {},
+      cwd: dataDir,
+    });
+    expect(result.exitCode).toBe(0);
+
+    await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
+      const list = await vaultOps.listSecrets(vault);
+      expect(list.sort()).toStrictEqual([]);
+    });
+  });
+});
diff --git a/tests/secrets/get.test.ts b/tests/secrets/get.test.ts
new file mode 100644
index 00000000..d2c3d0fb
--- /dev/null
+++ b/tests/secrets/get.test.ts
@@ -0,0 +1,72 @@
+import type { VaultName } from 'polykey/dist/vaults/types';
+import path from 'path';
+import fs from 'fs';
+import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
+import PolykeyAgent from 'polykey/dist/PolykeyAgent';
+import { vaultOps } from 'polykey/dist/vaults';
+import * as keysUtils from 'polykey/dist/keys/utils';
+import * as testUtils from '../utils';
+
+describe('commandGetSecret', () => {
+  const password = 'password';
+  const logger = new Logger('CLI Test', LogLevel.WARN, [new StreamHandler()]);
+  let dataDir: string;
+  let polykeyAgent: PolykeyAgent;
+  let passwordFile: string;
+  let command: Array<string>;
+
+  beforeEach(async () => {
+    dataDir = await fs.promises.mkdtemp(
+      path.join(globalThis.tmpDir, 'polykey-test-'),
+    );
+    passwordFile = path.join(dataDir, 'passwordFile');
+    await fs.promises.writeFile(passwordFile, 'password');
+    polykeyAgent = await PolykeyAgent.createPolykeyAgent({
+      password,
+      options: {
+        nodePath: dataDir,
+        agentServiceHost: '127.0.0.1',
+        clientServiceHost: '127.0.0.1',
+        keys: {
+          passwordOpsLimit: keysUtils.passwordOpsLimits.min,
+          passwordMemLimit: keysUtils.passwordMemLimits.min,
+          strictMemoryLock: false,
+        },
+      },
+      logger: logger,
+    });
+    // Authorize session
+    await testUtils.pkStdio(
+      ['agent', 'unlock', '-np', dataDir, '--password-file', passwordFile],
+      {
+        env: {},
+        cwd: dataDir,
+      },
+    );
+  });
+  afterEach(async () => {
+    await polykeyAgent.stop();
+    await fs.promises.rm(dataDir, {
+      force: true,
+      recursive: true,
+    });
+  });
+
+  test('should retrieve secrets', async () => {
+    const vaultName = 'Vault3' as VaultName;
+    const vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
+
+    await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
+      await vaultOps.addSecret(vault, 'MySecret', 'this is the secret');
+    });
+
+    command = ['secrets', 'get', '-np', dataDir, `${vaultName}:MySecret`];
+
+    const result = await testUtils.pkStdio([...command], {
+      env: {},
+      cwd: dataDir,
+    });
+    expect(result.stdout).toBe('this is the secret');
+    expect(result.exitCode).toBe(0);
+  });
+});
diff --git a/tests/secrets/list.test.ts b/tests/secrets/list.test.ts
new file mode 100644
index 00000000..f1b88b71
--- /dev/null
+++ b/tests/secrets/list.test.ts
@@ -0,0 +1,77 @@
+import type { VaultName } from 'polykey/dist/vaults/types';
+import path from 'path';
+import fs from 'fs';
+import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
+import PolykeyAgent from 'polykey/dist/PolykeyAgent';
+import { vaultOps } from 'polykey/dist/vaults';
+import * as keysUtils from 'polykey/dist/keys/utils';
+import * as testUtils from '../utils';
+
+describe('commandListSecrets', () => {
+  const password = 'password';
+  const logger = new Logger('CLI Test', LogLevel.WARN, [new StreamHandler()]);
+  let dataDir: string;
+  let polykeyAgent: PolykeyAgent;
+  let passwordFile: string;
+  let command: Array<string>;
+
+  beforeEach(async () => {
+    dataDir = await fs.promises.mkdtemp(
+      path.join(globalThis.tmpDir, 'polykey-test-'),
+    );
+    passwordFile = path.join(dataDir, 'passwordFile');
+    await fs.promises.writeFile(passwordFile, 'password');
+    polykeyAgent = await PolykeyAgent.createPolykeyAgent({
+      password,
+      options: {
+        nodePath: dataDir,
+        agentServiceHost: '127.0.0.1',
+        clientServiceHost: '127.0.0.1',
+        keys: {
+          passwordOpsLimit: keysUtils.passwordOpsLimits.min,
+          passwordMemLimit: keysUtils.passwordMemLimits.min,
+          strictMemoryLock: false,
+        },
+      },
+      logger: logger,
+    });
+    // Authorize session
+    await testUtils.pkStdio(
+      ['agent', 'unlock', '-np', dataDir, '--password-file', passwordFile],
+      {
+        env: {},
+        cwd: dataDir,
+      },
+    );
+  });
+  afterEach(async () => {
+    await polykeyAgent.stop();
+    await fs.promises.rm(dataDir, {
+      force: true,
+      recursive: true,
+    });
+  });
+
+  test(
+    'should list secrets',
+    async () => {
+      const vaultName = 'Vault4' as VaultName;
+      const vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
+
+      await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
+        await vaultOps.addSecret(vault, 'MySecret1', 'this is the secret 1');
+        await vaultOps.addSecret(vault, 'MySecret2', 'this is the secret 2');
+        await vaultOps.addSecret(vault, 'MySecret3', 'this is the secret 3');
+      });
+
+      command = ['secrets', 'list', '-np', dataDir, vaultName];
+
+      const result = await testUtils.pkStdio([...command], {
+        env: {},
+        cwd: dataDir,
+      });
+      expect(result.exitCode).toBe(0);
+    },
+    globalThis.defaultTimeout * 2,
+  );
+});
diff --git a/tests/secrets/newDir.test.ts b/tests/secrets/newDir.test.ts
new file mode 100644
index 00000000..74797011
--- /dev/null
+++ b/tests/secrets/newDir.test.ts
@@ -0,0 +1,88 @@
+import type { VaultName } from 'polykey/dist/vaults/types';
+import path from 'path';
+import fs from 'fs';
+import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
+import PolykeyAgent from 'polykey/dist/PolykeyAgent';
+import { vaultOps } from 'polykey/dist/vaults';
+import * as keysUtils from 'polykey/dist/keys/utils';
+import * as testUtils from '../utils';
+
+describe('commandNewDir', () => {
+  const password = 'password';
+  const logger = new Logger('CLI Test', LogLevel.WARN, [new StreamHandler()]);
+  let dataDir: string;
+  let polykeyAgent: PolykeyAgent;
+  let passwordFile: string;
+  let command: Array<string>;
+
+  beforeEach(async () => {
+    dataDir = await fs.promises.mkdtemp(
+      path.join(globalThis.tmpDir, 'polykey-test-'),
+    );
+    passwordFile = path.join(dataDir, 'passwordFile');
+    await fs.promises.writeFile(passwordFile, 'password');
+    polykeyAgent = await PolykeyAgent.createPolykeyAgent({
+      password,
+      options: {
+        nodePath: dataDir,
+        agentServiceHost: '127.0.0.1',
+        clientServiceHost: '127.0.0.1',
+        keys: {
+          passwordOpsLimit: keysUtils.passwordOpsLimits.min,
+          passwordMemLimit: keysUtils.passwordMemLimits.min,
+          strictMemoryLock: false,
+        },
+      },
+      logger: logger,
+    });
+    // Authorize session
+    await testUtils.pkStdio(
+      ['agent', 'unlock', '-np', dataDir, '--password-file', passwordFile],
+      {
+        env: {},
+        cwd: dataDir,
+      },
+    );
+  });
+  afterEach(async () => {
+    await polykeyAgent.stop();
+    await fs.promises.rm(dataDir, {
+      force: true,
+      recursive: true,
+    });
+  });
+
+  test('should make a directory', async () => {
+    const vaultName = 'Vault5' as VaultName;
+    const vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
+
+    command = [
+      'secrets',
+      'mkdir',
+      '-np',
+      dataDir,
+      `${vaultName}:dir1/dir2`,
+      '-r',
+    ];
+
+    const result = await testUtils.pkStdio([...command], {
+      env: {},
+      cwd: dataDir,
+    });
+    expect(result.exitCode).toBe(0);
+
+    await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
+      await vaultOps.addSecret(vault, 'dir1/MySecret1', 'this is the secret 1');
+      await vaultOps.addSecret(
+        vault,
+        'dir1/dir2/MySecret2',
+        'this is the secret 2',
+      );
+
+      const list = await vaultOps.listSecrets(vault);
+      expect(list.sort()).toStrictEqual(
+        ['dir1/MySecret1', 'dir1/dir2/MySecret2'].sort(),
+      );
+    });
+  });
+});
diff --git a/tests/secrets/newDirSecret.test.ts b/tests/secrets/newDirSecret.test.ts
new file mode 100644
index 00000000..9bdb9719
--- /dev/null
+++ b/tests/secrets/newDirSecret.test.ts
@@ -0,0 +1,96 @@
+import type { VaultName } from 'polykey/dist/vaults/types';
+import path from 'path';
+import fs from 'fs';
+import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
+import PolykeyAgent from 'polykey/dist/PolykeyAgent';
+import { vaultOps } from 'polykey/dist/vaults';
+import * as keysUtils from 'polykey/dist/keys/utils';
+import * as testUtils from '../utils';
+
+describe('commandNewDirSecret', () => {
+  const password = 'password';
+  const logger = new Logger('CLI Test', LogLevel.WARN, [new StreamHandler()]);
+  let dataDir: string;
+  let polykeyAgent: PolykeyAgent;
+  let passwordFile: string;
+  let command: Array<string>;
+
+  beforeEach(async () => {
+    dataDir = await fs.promises.mkdtemp(
+      path.join(globalThis.tmpDir, 'polykey-test-'),
+    );
+    passwordFile = path.join(dataDir, 'passwordFile');
+    await fs.promises.writeFile(passwordFile, 'password');
+    polykeyAgent = await PolykeyAgent.createPolykeyAgent({
+      password,
+      options: {
+        nodePath: dataDir,
+        agentServiceHost: '127.0.0.1',
+        clientServiceHost: '127.0.0.1',
+        keys: {
+          passwordOpsLimit: keysUtils.passwordOpsLimits.min,
+          passwordMemLimit: keysUtils.passwordMemLimits.min,
+          strictMemoryLock: false,
+        },
+      },
+      logger: logger,
+    });
+    // Authorize session
+    await testUtils.pkStdio(
+      ['agent', 'unlock', '-np', dataDir, '--password-file', passwordFile],
+      {
+        env: {},
+        cwd: dataDir,
+      },
+    );
+  });
+  afterEach(async () => {
+    await polykeyAgent.stop();
+    await fs.promises.rm(dataDir, {
+      force: true,
+      recursive: true,
+    });
+  });
+
+  test('should add a directory of secrets', async () => {
+    const vaultName = 'Vault8' as VaultName;
+    const vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
+
+    const secretDir = path.join(dataDir, 'secrets');
+    await fs.promises.mkdir(secretDir);
+    await fs.promises.writeFile(
+      path.join(secretDir, 'secret-1'),
+      'this is the secret 1',
+    );
+    await fs.promises.writeFile(
+      path.join(secretDir, 'secret-2'),
+      'this is the secret 2',
+    );
+    await fs.promises.writeFile(
+      path.join(secretDir, 'secret-3'),
+      'this is the secret 3',
+    );
+
+    await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
+      const list = await vaultOps.listSecrets(vault);
+      expect(list.sort()).toStrictEqual([]);
+    });
+
+    command = ['secrets', 'dir', '-np', dataDir, secretDir, vaultName];
+
+    const result2 = await testUtils.pkStdio([...command], {
+      env: {},
+      cwd: dataDir,
+    });
+    expect(result2.exitCode).toBe(0);
+
+    await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
+      const list = await vaultOps.listSecrets(vault);
+      expect(list.sort()).toStrictEqual([
+        'secrets/secret-1',
+        'secrets/secret-2',
+        'secrets/secret-3',
+      ]);
+    });
+  });
+});
diff --git a/tests/secrets/rename.test.ts b/tests/secrets/rename.test.ts
new file mode 100644
index 00000000..0e2aa903
--- /dev/null
+++ b/tests/secrets/rename.test.ts
@@ -0,0 +1,83 @@
+import type { VaultName } from 'polykey/dist/vaults/types';
+import path from 'path';
+import fs from 'fs';
+import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
+import PolykeyAgent from 'polykey/dist/PolykeyAgent';
+import { vaultOps } from 'polykey/dist/vaults';
+import * as keysUtils from 'polykey/dist/keys/utils';
+import * as testUtils from '../utils';
+
+describe('commandRenameSecret', () => {
+  const password = 'password';
+  const logger = new Logger('CLI Test', LogLevel.WARN, [new StreamHandler()]);
+  let dataDir: string;
+  let polykeyAgent: PolykeyAgent;
+  let passwordFile: string;
+  let command: Array<string>;
+
+  beforeEach(async () => {
+    dataDir = await fs.promises.mkdtemp(
+      path.join(globalThis.tmpDir, 'polykey-test-'),
+    );
+    passwordFile = path.join(dataDir, 'passwordFile');
+    await fs.promises.writeFile(passwordFile, 'password');
+    polykeyAgent = await PolykeyAgent.createPolykeyAgent({
+      password,
+      options: {
+        nodePath: dataDir,
+        agentServiceHost: '127.0.0.1',
+        clientServiceHost: '127.0.0.1',
+        keys: {
+          passwordOpsLimit: keysUtils.passwordOpsLimits.min,
+          passwordMemLimit: keysUtils.passwordMemLimits.min,
+          strictMemoryLock: false,
+        },
+      },
+      logger: logger,
+    });
+    // Authorize session
+    await testUtils.pkStdio(
+      ['agent', 'unlock', '-np', dataDir, '--password-file', passwordFile],
+      {
+        env: {},
+        cwd: dataDir,
+      },
+    );
+  });
+  afterEach(async () => {
+    await polykeyAgent.stop();
+    await fs.promises.rm(dataDir, {
+      force: true,
+      recursive: true,
+    });
+  });
+
+  test('should rename secrets', async () => {
+    const vaultName = 'Vault6' as VaultName;
+    const vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
+
+    await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
+      await vaultOps.addSecret(vault, 'MySecret', 'this is the secret');
+    });
+
+    command = [
+      'secrets',
+      'rename',
+      '-np',
+      dataDir,
+      `${vaultName}:MySecret`,
+      'MyRenamedSecret',
+    ];
+
+    const result = await testUtils.pkStdio([...command], {
+      env: {},
+      cwd: dataDir,
+    });
+    expect(result.exitCode).toBe(0);
+
+    await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
+      const list = await vaultOps.listSecrets(vault);
+      expect(list.sort()).toStrictEqual(['MyRenamedSecret']);
+    });
+  });
+});
diff --git a/tests/secrets/secrets.test.ts b/tests/secrets/secrets.test.ts
deleted file mode 100644
index 829fc939..00000000
--- a/tests/secrets/secrets.test.ts
+++ /dev/null
@@ -1,331 +0,0 @@
-import type { VaultName } from 'polykey/dist/vaults/types';
-import path from 'path';
-import fs from 'fs';
-import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
-import PolykeyAgent from 'polykey/dist/PolykeyAgent';
-import { vaultOps } from 'polykey/dist/vaults';
-import * as keysUtils from 'polykey/dist/keys/utils';
-import * as testUtils from '../utils';
-
-describe('CLI secrets', () => {
-  const password = 'password';
-  const logger = new Logger('CLI Test', LogLevel.WARN, [new StreamHandler()]);
-  let dataDir: string;
-  let polykeyAgent: PolykeyAgent;
-  let passwordFile: string;
-  let command: Array<string>;
-
-  beforeEach(async () => {
-    dataDir = await fs.promises.mkdtemp(
-      path.join(globalThis.tmpDir, 'polykey-test-'),
-    );
-    passwordFile = path.join(dataDir, 'passwordFile');
-    await fs.promises.writeFile(passwordFile, 'password');
-    polykeyAgent = await PolykeyAgent.createPolykeyAgent({
-      password,
-      options: {
-        nodePath: dataDir,
-        agentServiceHost: '127.0.0.1',
-        clientServiceHost: '127.0.0.1',
-        keys: {
-          passwordOpsLimit: keysUtils.passwordOpsLimits.min,
-          passwordMemLimit: keysUtils.passwordMemLimits.min,
-          strictMemoryLock: false,
-        },
-      },
-      logger: logger,
-    });
-    // Authorize session
-    await testUtils.pkStdio(
-      ['agent', 'unlock', '-np', dataDir, '--password-file', passwordFile],
-      {
-        env: {},
-        cwd: dataDir,
-      },
-    );
-  });
-  afterEach(async () => {
-    await polykeyAgent.stop();
-    await fs.promises.rm(dataDir, {
-      force: true,
-      recursive: true,
-    });
-  });
-
-  describe('commandCreateSecret', () => {
-    test(
-      'should create secrets',
-      async () => {
-        const vaultName = 'Vault1' as VaultName;
-        const vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
-        const secretPath = path.join(dataDir, 'secret');
-        await fs.promises.writeFile(secretPath, 'this is a secret');
-
-        command = [
-          'secrets',
-          'create',
-          '-np',
-          dataDir,
-          secretPath,
-          `${vaultName}:MySecret`,
-        ];
-
-        const result = await testUtils.pkStdio([...command], {
-          env: {},
-          cwd: dataDir,
-        });
-        expect(result.exitCode).toBe(0);
-
-        await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
-          const list = await vaultOps.listSecrets(vault);
-          expect(list.sort()).toStrictEqual(['MySecret']);
-          expect(
-            (await vaultOps.getSecret(vault, 'MySecret')).toString(),
-          ).toStrictEqual('this is a secret');
-        });
-      },
-      globalThis.defaultTimeout * 2,
-    );
-  });
-  describe('commandDeleteSecret', () => {
-    test('should delete secrets', async () => {
-      const vaultName = 'Vault2' as VaultName;
-      const vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
-
-      await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
-        await vaultOps.addSecret(vault, 'MySecret', 'this is the secret');
-        const list = await vaultOps.listSecrets(vault);
-        expect(list.sort()).toStrictEqual(['MySecret']);
-      });
-
-      command = ['secrets', 'delete', '-np', dataDir, `${vaultName}:MySecret`];
-
-      const result = await testUtils.pkStdio([...command], {
-        env: {},
-        cwd: dataDir,
-      });
-      expect(result.exitCode).toBe(0);
-
-      await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
-        const list = await vaultOps.listSecrets(vault);
-        expect(list.sort()).toStrictEqual([]);
-      });
-    });
-  });
-  describe('commandGetSecret', () => {
-    test('should retrieve secrets', async () => {
-      const vaultName = 'Vault3' as VaultName;
-      const vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
-
-      await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
-        await vaultOps.addSecret(vault, 'MySecret', 'this is the secret');
-      });
-
-      command = ['secrets', 'get', '-np', dataDir, `${vaultName}:MySecret`];
-
-      const result = await testUtils.pkStdio([...command], {
-        env: {},
-        cwd: dataDir,
-      });
-      expect(result.stdout).toBe('this is the secret');
-      expect(result.exitCode).toBe(0);
-    });
-  });
-  describe('commandListSecrets', () => {
-    test(
-      'should list secrets',
-      async () => {
-        const vaultName = 'Vault4' as VaultName;
-        const vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
-
-        await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
-          await vaultOps.addSecret(vault, 'MySecret1', 'this is the secret 1');
-          await vaultOps.addSecret(vault, 'MySecret2', 'this is the secret 2');
-          await vaultOps.addSecret(vault, 'MySecret3', 'this is the secret 3');
-        });
-
-        command = ['secrets', 'list', '-np', dataDir, vaultName];
-
-        const result = await testUtils.pkStdio([...command], {
-          env: {},
-          cwd: dataDir,
-        });
-        expect(result.exitCode).toBe(0);
-      },
-      globalThis.defaultTimeout * 2,
-    );
-  });
-  describe('commandNewDir', () => {
-    test('should make a directory', async () => {
-      const vaultName = 'Vault5' as VaultName;
-      const vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
-
-      command = [
-        'secrets',
-        'mkdir',
-        '-np',
-        dataDir,
-        `${vaultName}:dir1/dir2`,
-        '-r',
-      ];
-
-      const result = await testUtils.pkStdio([...command], {
-        env: {},
-        cwd: dataDir,
-      });
-      expect(result.exitCode).toBe(0);
-
-      await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
-        await vaultOps.addSecret(
-          vault,
-          'dir1/MySecret1',
-          'this is the secret 1',
-        );
-        await vaultOps.addSecret(
-          vault,
-          'dir1/dir2/MySecret2',
-          'this is the secret 2',
-        );
-
-        const list = await vaultOps.listSecrets(vault);
-        expect(list.sort()).toStrictEqual(
-          ['dir1/MySecret1', 'dir1/dir2/MySecret2'].sort(),
-        );
-      });
-    });
-  });
-  describe('commandRenameSecret', () => {
-    test('should rename secrets', async () => {
-      const vaultName = 'Vault6' as VaultName;
-      const vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
-
-      await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
-        await vaultOps.addSecret(vault, 'MySecret', 'this is the secret');
-      });
-
-      command = [
-        'secrets',
-        'rename',
-        '-np',
-        dataDir,
-        `${vaultName}:MySecret`,
-        'MyRenamedSecret',
-      ];
-
-      const result = await testUtils.pkStdio([...command], {
-        env: {},
-        cwd: dataDir,
-      });
-      expect(result.exitCode).toBe(0);
-
-      await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
-        const list = await vaultOps.listSecrets(vault);
-        expect(list.sort()).toStrictEqual(['MyRenamedSecret']);
-      });
-    });
-  });
-  describe('commandUpdateSecret', () => {
-    test('should update secrets', async () => {
-      const vaultName = 'Vault7' as VaultName;
-      const vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
-
-      const secretPath = path.join(dataDir, 'secret');
-      await fs.promises.writeFile(secretPath, 'updated-content');
-
-      await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
-        await vaultOps.addSecret(vault, 'MySecret', 'original-content');
-        expect(
-          (await vaultOps.getSecret(vault, 'MySecret')).toString(),
-        ).toStrictEqual('original-content');
-      });
-
-      command = [
-        'secrets',
-        'update',
-        '-np',
-        dataDir,
-        secretPath,
-        `${vaultName}:MySecret`,
-      ];
-
-      const result2 = await testUtils.pkStdio([...command], {
-        env: {},
-        cwd: dataDir,
-      });
-      expect(result2.exitCode).toBe(0);
-
-      await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
-        const list = await vaultOps.listSecrets(vault);
-        expect(list.sort()).toStrictEqual(['MySecret']);
-        expect(
-          (await vaultOps.getSecret(vault, 'MySecret')).toString(),
-        ).toStrictEqual('updated-content');
-      });
-    });
-  });
-  describe('commandNewDirSecret', () => {
-    test('should add a directory of secrets', async () => {
-      const vaultName = 'Vault8' as VaultName;
-      const vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
-
-      const secretDir = path.join(dataDir, 'secrets');
-      await fs.promises.mkdir(secretDir);
-      await fs.promises.writeFile(
-        path.join(secretDir, 'secret-1'),
-        'this is the secret 1',
-      );
-      await fs.promises.writeFile(
-        path.join(secretDir, 'secret-2'),
-        'this is the secret 2',
-      );
-      await fs.promises.writeFile(
-        path.join(secretDir, 'secret-3'),
-        'this is the secret 3',
-      );
-
-      await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
-        const list = await vaultOps.listSecrets(vault);
-        expect(list.sort()).toStrictEqual([]);
-      });
-
-      command = ['secrets', 'dir', '-np', dataDir, secretDir, vaultName];
-
-      const result2 = await testUtils.pkStdio([...command], {
-        env: {},
-        cwd: dataDir,
-      });
-      expect(result2.exitCode).toBe(0);
-
-      await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
-        const list = await vaultOps.listSecrets(vault);
-        expect(list.sort()).toStrictEqual([
-          'secrets/secret-1',
-          'secrets/secret-2',
-          'secrets/secret-3',
-        ]);
-      });
-    });
-  });
-  describe('commandStat', () => {
-    test('should retrieve secrets', async () => {
-      const vaultName = 'Vault9';
-      const vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
-
-      await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
-        await vaultOps.addSecret(vault, 'MySecret', 'this is the secret');
-      });
-
-      command = ['secrets', 'stat', '-np', dataDir, `${vaultName}:MySecret`];
-
-      const result = await testUtils.pkStdio([...command], {
-        env: {},
-        cwd: dataDir,
-      });
-      expect(result.exitCode).toBe(0);
-      expect(result.stdout).toContain('nlink: 1');
-      expect(result.stdout).toContain('blocks: 1');
-      expect(result.stdout).toContain('blksize: 4096');
-      expect(result.stdout).toContain('size: 18');
-    });
-  });
-});
diff --git a/tests/secrets/stat.test.ts b/tests/secrets/stat.test.ts
new file mode 100644
index 00000000..95cbe51c
--- /dev/null
+++ b/tests/secrets/stat.test.ts
@@ -0,0 +1,74 @@
+import path from 'path';
+import fs from 'fs';
+import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
+import PolykeyAgent from 'polykey/dist/PolykeyAgent';
+import { vaultOps } from 'polykey/dist/vaults';
+import * as keysUtils from 'polykey/dist/keys/utils';
+import * as testUtils from '../utils';
+
+describe('commandStat', () => {
+  const password = 'password';
+  const logger = new Logger('CLI Test', LogLevel.WARN, [new StreamHandler()]);
+  let dataDir: string;
+  let polykeyAgent: PolykeyAgent;
+  let passwordFile: string;
+  let command: Array<string>;
+
+  beforeEach(async () => {
+    dataDir = await fs.promises.mkdtemp(
+      path.join(globalThis.tmpDir, 'polykey-test-'),
+    );
+    passwordFile = path.join(dataDir, 'passwordFile');
+    await fs.promises.writeFile(passwordFile, 'password');
+    polykeyAgent = await PolykeyAgent.createPolykeyAgent({
+      password,
+      options: {
+        nodePath: dataDir,
+        agentServiceHost: '127.0.0.1',
+        clientServiceHost: '127.0.0.1',
+        keys: {
+          passwordOpsLimit: keysUtils.passwordOpsLimits.min,
+          passwordMemLimit: keysUtils.passwordMemLimits.min,
+          strictMemoryLock: false,
+        },
+      },
+      logger: logger,
+    });
+    // Authorize session
+    await testUtils.pkStdio(
+      ['agent', 'unlock', '-np', dataDir, '--password-file', passwordFile],
+      {
+        env: {},
+        cwd: dataDir,
+      },
+    );
+  });
+  afterEach(async () => {
+    await polykeyAgent.stop();
+    await fs.promises.rm(dataDir, {
+      force: true,
+      recursive: true,
+    });
+  });
+
+  test('should retrieve secrets', async () => {
+    const vaultName = 'Vault9';
+    const vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
+
+    await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
+      await vaultOps.addSecret(vault, 'MySecret', 'this is the secret');
+    });
+
+    command = ['secrets', 'stat', '-np', dataDir, `${vaultName}:MySecret`];
+
+    const result = await testUtils.pkStdio([...command], {
+      env: {},
+      cwd: dataDir,
+    });
+    expect(result.exitCode).toBe(0);
+    expect(result.stdout).toContain('nlink: 1');
+    expect(result.stdout).toContain('blocks: 1');
+    expect(result.stdout).toContain('blksize: 4096');
+    expect(result.stdout).toContain('size: 18');
+  });
+});
diff --git a/tests/secrets/uopdate.test.ts b/tests/secrets/uopdate.test.ts
new file mode 100644
index 00000000..9cb9969e
--- /dev/null
+++ b/tests/secrets/uopdate.test.ts
@@ -0,0 +1,92 @@
+import type { VaultName } from 'polykey/dist/vaults/types';
+import path from 'path';
+import fs from 'fs';
+import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
+import PolykeyAgent from 'polykey/dist/PolykeyAgent';
+import { vaultOps } from 'polykey/dist/vaults';
+import * as keysUtils from 'polykey/dist/keys/utils';
+import * as testUtils from '../utils';
+
+describe('commandUpdateSecret', () => {
+  const password = 'password';
+  const logger = new Logger('CLI Test', LogLevel.WARN, [new StreamHandler()]);
+  let dataDir: string;
+  let polykeyAgent: PolykeyAgent;
+  let passwordFile: string;
+  let command: Array<string>;
+
+  beforeEach(async () => {
+    dataDir = await fs.promises.mkdtemp(
+      path.join(globalThis.tmpDir, 'polykey-test-'),
+    );
+    passwordFile = path.join(dataDir, 'passwordFile');
+    await fs.promises.writeFile(passwordFile, 'password');
+    polykeyAgent = await PolykeyAgent.createPolykeyAgent({
+      password,
+      options: {
+        nodePath: dataDir,
+        agentServiceHost: '127.0.0.1',
+        clientServiceHost: '127.0.0.1',
+        keys: {
+          passwordOpsLimit: keysUtils.passwordOpsLimits.min,
+          passwordMemLimit: keysUtils.passwordMemLimits.min,
+          strictMemoryLock: false,
+        },
+      },
+      logger: logger,
+    });
+    // Authorize session
+    await testUtils.pkStdio(
+      ['agent', 'unlock', '-np', dataDir, '--password-file', passwordFile],
+      {
+        env: {},
+        cwd: dataDir,
+      },
+    );
+  });
+  afterEach(async () => {
+    await polykeyAgent.stop();
+    await fs.promises.rm(dataDir, {
+      force: true,
+      recursive: true,
+    });
+  });
+
+  test('should update secrets', async () => {
+    const vaultName = 'Vault7' as VaultName;
+    const vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
+
+    const secretPath = path.join(dataDir, 'secret');
+    await fs.promises.writeFile(secretPath, 'updated-content');
+
+    await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
+      await vaultOps.addSecret(vault, 'MySecret', 'original-content');
+      expect(
+        (await vaultOps.getSecret(vault, 'MySecret')).toString(),
+      ).toStrictEqual('original-content');
+    });
+
+    command = [
+      'secrets',
+      'update',
+      '-np',
+      dataDir,
+      secretPath,
+      `${vaultName}:MySecret`,
+    ];
+
+    const result2 = await testUtils.pkStdio([...command], {
+      env: {},
+      cwd: dataDir,
+    });
+    expect(result2.exitCode).toBe(0);
+
+    await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
+      const list = await vaultOps.listSecrets(vault);
+      expect(list.sort()).toStrictEqual(['MySecret']);
+      expect(
+        (await vaultOps.getSecret(vault, 'MySecret')).toString(),
+      ).toStrictEqual('updated-content');
+    });
+  });
+});
diff --git a/tests/vaults/create.test.ts b/tests/vaults/create.test.ts
new file mode 100644
index 00000000..2c942a6b
--- /dev/null
+++ b/tests/vaults/create.test.ts
@@ -0,0 +1,96 @@
+import type { GestaltNodeInfo } from 'polykey/dist/gestalts/types';
+import path from 'path';
+import fs from 'fs';
+import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
+import PolykeyAgent from 'polykey/dist/PolykeyAgent';
+import * as ids from 'polykey/dist/ids';
+import * as keysUtils from 'polykey/dist/keys/utils';
+import * as testUtils from '../utils';
+
+describe('commandCreateVaults', () => {
+  const password = 'password';
+  const logger = new Logger('CLI Test', LogLevel.WARN, [new StreamHandler()]);
+  let dataDir: string;
+  let passwordFile: string;
+  let polykeyAgent: PolykeyAgent;
+  let command: Array<string>;
+  const nodeIdGenerator = ids.createNodeIdGenerator();
+  const nodeId1 = nodeIdGenerator();
+  const nodeId2 = nodeIdGenerator();
+  const nodeId3 = nodeIdGenerator();
+  const node1: GestaltNodeInfo = {
+    nodeId: nodeId1,
+  };
+  const node2: GestaltNodeInfo = {
+    nodeId: nodeId2,
+  };
+  const node3: GestaltNodeInfo = {
+    nodeId: nodeId3,
+  };
+  beforeEach(async () => {
+    dataDir = await fs.promises.mkdtemp(
+      path.join(globalThis.tmpDir, 'polykey-test-'),
+    );
+    passwordFile = path.join(dataDir, 'passwordFile');
+    await fs.promises.writeFile(passwordFile, 'password');
+    polykeyAgent = await PolykeyAgent.createPolykeyAgent({
+      password,
+      options: {
+        nodePath: dataDir,
+        agentServiceHost: '127.0.0.1',
+        clientServiceHost: '127.0.0.1',
+        keys: {
+          passwordOpsLimit: keysUtils.passwordOpsLimits.min,
+          passwordMemLimit: keysUtils.passwordMemLimits.min,
+          strictMemoryLock: false,
+        },
+      },
+      logger: logger,
+    });
+    await polykeyAgent.gestaltGraph.setNode(node1);
+    await polykeyAgent.gestaltGraph.setNode(node2);
+    await polykeyAgent.gestaltGraph.setNode(node3);
+
+    // Authorize session
+    await testUtils.pkStdio(
+      ['agent', 'unlock', '-np', dataDir, '--password-file', passwordFile],
+      {
+        env: {},
+        cwd: dataDir,
+      },
+    );
+    command = [];
+  });
+  afterEach(async () => {
+    await polykeyAgent.stop();
+    await fs.promises.rm(dataDir, {
+      force: true,
+      recursive: true,
+    });
+  });
+
+  test('should create vaults', async () => {
+    command = ['vaults', 'create', '-np', dataDir, 'MyTestVault'];
+    const result = await testUtils.pkStdio([...command], {
+      env: {},
+      cwd: dataDir,
+    });
+    expect(result.exitCode).toBe(0);
+    const result2 = await testUtils.pkStdio(
+      ['vaults', 'touch', '-np', dataDir, 'MyTestVault2'],
+      {
+        env: {},
+        cwd: dataDir,
+      },
+    );
+    expect(result2.exitCode).toBe(0);
+
+    const list = (await polykeyAgent.vaultManager.listVaults()).keys();
+    const namesList: string[] = [];
+    for await (const name of list) {
+      namesList.push(name);
+    }
+    expect(namesList).toContain('MyTestVault');
+    expect(namesList).toContain('MyTestVault2');
+  });
+});
diff --git a/tests/vaults/delete.test.ts b/tests/vaults/delete.test.ts
new file mode 100644
index 00000000..30bbee6a
--- /dev/null
+++ b/tests/vaults/delete.test.ts
@@ -0,0 +1,105 @@
+import type { VaultName } from 'polykey/dist/vaults/types';
+import type { GestaltNodeInfo } from 'polykey/dist/gestalts/types';
+import path from 'path';
+import fs from 'fs';
+import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
+import PolykeyAgent from 'polykey/dist/PolykeyAgent';
+import * as ids from 'polykey/dist/ids';
+import * as keysUtils from 'polykey/dist/keys/utils';
+import * as testUtils from '../utils';
+
+describe('commandDeleteVault', () => {
+  const password = 'password';
+  const logger = new Logger('CLI Test', LogLevel.WARN, [new StreamHandler()]);
+  let dataDir: string;
+  let passwordFile: string;
+  let polykeyAgent: PolykeyAgent;
+  let command: Array<string>;
+  let vaultNumber: number;
+  let vaultName: VaultName;
+  const nodeIdGenerator = ids.createNodeIdGenerator();
+  const nodeId1 = nodeIdGenerator();
+  const nodeId2 = nodeIdGenerator();
+  const nodeId3 = nodeIdGenerator();
+  const node1: GestaltNodeInfo = {
+    nodeId: nodeId1,
+  };
+  const node2: GestaltNodeInfo = {
+    nodeId: nodeId2,
+  };
+  const node3: GestaltNodeInfo = {
+    nodeId: nodeId3,
+  };
+  // Helper functions
+  function genVaultName() {
+    vaultNumber++;
+    return `vault-${vaultNumber}` as VaultName;
+  }
+  beforeEach(async () => {
+    dataDir = await fs.promises.mkdtemp(
+      path.join(globalThis.tmpDir, 'polykey-test-'),
+    );
+    passwordFile = path.join(dataDir, 'passwordFile');
+    await fs.promises.writeFile(passwordFile, 'password');
+    polykeyAgent = await PolykeyAgent.createPolykeyAgent({
+      password,
+      options: {
+        nodePath: dataDir,
+        agentServiceHost: '127.0.0.1',
+        clientServiceHost: '127.0.0.1',
+        keys: {
+          passwordOpsLimit: keysUtils.passwordOpsLimits.min,
+          passwordMemLimit: keysUtils.passwordMemLimits.min,
+          strictMemoryLock: false,
+        },
+      },
+      logger: logger,
+    });
+    await polykeyAgent.gestaltGraph.setNode(node1);
+    await polykeyAgent.gestaltGraph.setNode(node2);
+    await polykeyAgent.gestaltGraph.setNode(node3);
+
+    vaultNumber = 0;
+
+    // Authorize session
+    await testUtils.pkStdio(
+      ['agent', 'unlock', '-np', dataDir, '--password-file', passwordFile],
+      {
+        env: {},
+        cwd: dataDir,
+      },
+    );
+    vaultName = genVaultName();
+    command = [];
+  });
+  afterEach(async () => {
+    await polykeyAgent.stop();
+    await fs.promises.rm(dataDir, {
+      force: true,
+      recursive: true,
+    });
+  });
+
+  test('should delete vault', async () => {
+    command = ['vaults', 'delete', '-np', dataDir, vaultName];
+    await polykeyAgent.vaultManager.createVault(vaultName);
+    let id = polykeyAgent.vaultManager.getVaultId(vaultName);
+    expect(id).toBeTruthy();
+
+    id = polykeyAgent.vaultManager.getVaultId(vaultName);
+    expect(id).toBeTruthy();
+
+    const result2 = await testUtils.pkStdio([...command], {
+      env: {},
+      cwd: dataDir,
+    });
+    expect(result2.exitCode).toBe(0);
+
+    const list = (await polykeyAgent.vaultManager.listVaults()).keys();
+    const namesList: string[] = [];
+    for await (const name of list) {
+      namesList.push(name);
+    }
+    expect(namesList).not.toContain(vaultName);
+  });
+});
diff --git a/tests/vaults/list.test.ts b/tests/vaults/list.test.ts
new file mode 100644
index 00000000..131e02ec
--- /dev/null
+++ b/tests/vaults/list.test.ts
@@ -0,0 +1,84 @@
+import type { VaultName } from 'polykey/dist/vaults/types';
+import type { GestaltNodeInfo } from 'polykey/dist/gestalts/types';
+import path from 'path';
+import fs from 'fs';
+import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
+import PolykeyAgent from 'polykey/dist/PolykeyAgent';
+import * as ids from 'polykey/dist/ids';
+import * as keysUtils from 'polykey/dist/keys/utils';
+import * as testUtils from '../utils';
+
+describe('commandListVaults', () => {
+  const password = 'password';
+  const logger = new Logger('CLI Test', LogLevel.WARN, [new StreamHandler()]);
+  let dataDir: string;
+  let passwordFile: string;
+  let polykeyAgent: PolykeyAgent;
+  let command: Array<string>;
+  const nodeIdGenerator = ids.createNodeIdGenerator();
+  const nodeId1 = nodeIdGenerator();
+  const nodeId2 = nodeIdGenerator();
+  const nodeId3 = nodeIdGenerator();
+  const node1: GestaltNodeInfo = {
+    nodeId: nodeId1,
+  };
+  const node2: GestaltNodeInfo = {
+    nodeId: nodeId2,
+  };
+  const node3: GestaltNodeInfo = {
+    nodeId: nodeId3,
+  };
+  beforeEach(async () => {
+    dataDir = await fs.promises.mkdtemp(
+      path.join(globalThis.tmpDir, 'polykey-test-'),
+    );
+    passwordFile = path.join(dataDir, 'passwordFile');
+    await fs.promises.writeFile(passwordFile, 'password');
+    polykeyAgent = await PolykeyAgent.createPolykeyAgent({
+      password,
+      options: {
+        nodePath: dataDir,
+        agentServiceHost: '127.0.0.1',
+        clientServiceHost: '127.0.0.1',
+        keys: {
+          passwordOpsLimit: keysUtils.passwordOpsLimits.min,
+          passwordMemLimit: keysUtils.passwordMemLimits.min,
+          strictMemoryLock: false,
+        },
+      },
+      logger: logger,
+    });
+    await polykeyAgent.gestaltGraph.setNode(node1);
+    await polykeyAgent.gestaltGraph.setNode(node2);
+    await polykeyAgent.gestaltGraph.setNode(node3);
+
+    // Authorize session
+    await testUtils.pkStdio(
+      ['agent', 'unlock', '-np', dataDir, '--password-file', passwordFile],
+      {
+        env: {},
+        cwd: dataDir,
+      },
+    );
+    command = [];
+  });
+  afterEach(async () => {
+    await polykeyAgent.stop();
+    await fs.promises.rm(dataDir, {
+      force: true,
+      recursive: true,
+    });
+  });
+
+  test('should list all vaults', async () => {
+    command = ['vaults', 'list', '-np', dataDir];
+    await polykeyAgent.vaultManager.createVault('Vault1' as VaultName);
+    await polykeyAgent.vaultManager.createVault('Vault2' as VaultName);
+
+    const result = await testUtils.pkStdio([...command], {
+      env: {},
+      cwd: dataDir,
+    });
+    expect(result.exitCode).toBe(0);
+  });
+});
diff --git a/tests/vaults/log.test.ts b/tests/vaults/log.test.ts
new file mode 100644
index 00000000..513faa4f
--- /dev/null
+++ b/tests/vaults/log.test.ts
@@ -0,0 +1,158 @@
+import type { VaultId, VaultName } from 'polykey/dist/vaults/types';
+import type { GestaltNodeInfo } from 'polykey/dist/gestalts/types';
+import path from 'path';
+import fs from 'fs';
+import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
+import PolykeyAgent from 'polykey/dist/PolykeyAgent';
+import * as ids from 'polykey/dist/ids';
+import * as keysUtils from 'polykey/dist/keys/utils';
+import * as testUtils from '../utils';
+
+describe('commandVaultLog', () => {
+  const password = 'password';
+  const logger = new Logger('CLI Test', LogLevel.WARN, [new StreamHandler()]);
+  const secret1 = { name: 'secret1', content: 'Secret-1-content' };
+  const secret2 = { name: 'secret2', content: 'Secret-2-content' };
+
+  let dataDir: string;
+  let passwordFile: string;
+  let polykeyAgent: PolykeyAgent;
+  let vaultNumber: number;
+  let vaultName: VaultName;
+  let vaultId: VaultId;
+  let writeF1Oid: string;
+  let writeF2Oid: string;
+  let writeF3Oid: string;
+
+  const nodeIdGenerator = ids.createNodeIdGenerator();
+  const nodeId1 = nodeIdGenerator();
+  const nodeId2 = nodeIdGenerator();
+  const nodeId3 = nodeIdGenerator();
+  const node1: GestaltNodeInfo = {
+    nodeId: nodeId1,
+  };
+  const node2: GestaltNodeInfo = {
+    nodeId: nodeId2,
+  };
+  const node3: GestaltNodeInfo = {
+    nodeId: nodeId3,
+  };
+  // Helper functions
+  function genVaultName() {
+    vaultNumber++;
+    return `vault-${vaultNumber}` as VaultName;
+  }
+
+  beforeEach(async () => {
+    dataDir = await fs.promises.mkdtemp(
+      path.join(globalThis.tmpDir, 'polykey-test-'),
+    );
+    passwordFile = path.join(dataDir, 'passwordFile');
+    await fs.promises.writeFile(passwordFile, 'password');
+    polykeyAgent = await PolykeyAgent.createPolykeyAgent({
+      password,
+      options: {
+        nodePath: dataDir,
+        agentServiceHost: '127.0.0.1',
+        clientServiceHost: '127.0.0.1',
+        keys: {
+          passwordOpsLimit: keysUtils.passwordOpsLimits.min,
+          passwordMemLimit: keysUtils.passwordMemLimits.min,
+          strictMemoryLock: false,
+        },
+      },
+      logger: logger,
+    });
+    await polykeyAgent.gestaltGraph.setNode(node1);
+    await polykeyAgent.gestaltGraph.setNode(node2);
+    await polykeyAgent.gestaltGraph.setNode(node3);
+
+    vaultNumber = 0;
+
+    // Authorize session
+    await testUtils.pkStdio(
+      ['agent', 'unlock', '-np', dataDir, '--password-file', passwordFile],
+      {
+        env: {},
+        cwd: dataDir,
+      },
+    );
+    vaultName = genVaultName();
+
+    vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
+
+    await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
+      await vault.writeF(async (efs) => {
+        await efs.writeFile(secret1.name, secret1.content);
+      });
+      writeF1Oid = (await vault.log(undefined, 0))[0].commitId;
+
+      await vault.writeF(async (efs) => {
+        await efs.writeFile(secret2.name, secret2.content);
+      });
+      writeF2Oid = (await vault.log(undefined, 0))[0].commitId;
+
+      await vault.writeF(async (efs) => {
+        await efs.unlink(secret2.name);
+      });
+      writeF3Oid = (await vault.log(undefined, 0))[0].commitId;
+    });
+  });
+  afterEach(async () => {
+    await polykeyAgent.vaultManager.destroyVault(vaultId);
+
+    await polykeyAgent.stop();
+    await fs.promises.rm(dataDir, {
+      force: true,
+      recursive: true,
+    });
+  });
+
+  test('Should get all writeFs', async () => {
+    const command = ['vaults', 'log', '-np', dataDir, vaultName];
+
+    const result = await testUtils.pkStdio([...command], {
+      env: {},
+      cwd: dataDir,
+    });
+    expect(result.exitCode).toEqual(0);
+    expect(result.stdout).toContain(writeF1Oid);
+    expect(result.stdout).toContain(writeF2Oid);
+    expect(result.stdout).toContain(writeF3Oid);
+  });
+  test('should get a part of the log', async () => {
+    const command = ['vaults', 'log', '-np', dataDir, '-d', '2', vaultName];
+
+    const result = await testUtils.pkStdio([...command], {
+      env: {},
+      cwd: dataDir,
+    });
+    expect(result.exitCode).toEqual(0);
+    expect(result.stdout).not.toContain(writeF1Oid);
+    expect(result.stdout).toContain(writeF2Oid);
+    expect(result.stdout).toContain(writeF3Oid);
+  });
+  test('should get a specific writeF', async () => {
+    const command = [
+      'vaults',
+      'log',
+      '-np',
+      dataDir,
+      '-d',
+      '1',
+      vaultName,
+      '-ci',
+      writeF2Oid,
+    ];
+
+    const result = await testUtils.pkStdio([...command], {
+      env: {},
+      cwd: dataDir,
+    });
+    expect(result.exitCode).toEqual(0);
+    expect(result.stdout).not.toContain(writeF1Oid);
+    expect(result.stdout).toContain(writeF2Oid);
+    expect(result.stdout).not.toContain(writeF3Oid);
+  });
+  test.todo('test formatting of the output');
+});
diff --git a/tests/vaults/permissions.test.ts b/tests/vaults/permissions.test.ts
new file mode 100644
index 00000000..121ed369
--- /dev/null
+++ b/tests/vaults/permissions.test.ts
@@ -0,0 +1,127 @@
+import type { VaultName } from 'polykey/dist/vaults/types';
+import type { GestaltNodeInfo } from 'polykey/dist/gestalts/types';
+import path from 'path';
+import fs from 'fs';
+import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
+import PolykeyAgent from 'polykey/dist/PolykeyAgent';
+import * as ids from 'polykey/dist/ids';
+import * as nodesUtils from 'polykey/dist/nodes/utils';
+import * as vaultsUtils from 'polykey/dist/vaults/utils';
+import * as keysUtils from 'polykey/dist/keys/utils';
+import * as testUtils from '../utils';
+
+describe('commandPermissions', () => {
+  const password = 'password';
+  const logger = new Logger('CLI Test', LogLevel.WARN, [new StreamHandler()]);
+  let dataDir: string;
+  let passwordFile: string;
+  let polykeyAgent: PolykeyAgent;
+  let command: Array<string>;
+  let vaultNumber: number;
+  let vaultName: VaultName;
+  const nodeIdGenerator = ids.createNodeIdGenerator();
+  const nodeId1 = nodeIdGenerator();
+  const nodeId2 = nodeIdGenerator();
+  const nodeId3 = nodeIdGenerator();
+  const node1: GestaltNodeInfo = {
+    nodeId: nodeId1,
+  };
+  const node2: GestaltNodeInfo = {
+    nodeId: nodeId2,
+  };
+  const node3: GestaltNodeInfo = {
+    nodeId: nodeId3,
+  };
+  // Helper functions
+  function genVaultName() {
+    vaultNumber++;
+    return `vault-${vaultNumber}` as VaultName;
+  }
+  beforeEach(async () => {
+    dataDir = await fs.promises.mkdtemp(
+      path.join(globalThis.tmpDir, 'polykey-test-'),
+    );
+    passwordFile = path.join(dataDir, 'passwordFile');
+    await fs.promises.writeFile(passwordFile, 'password');
+    polykeyAgent = await PolykeyAgent.createPolykeyAgent({
+      password,
+      options: {
+        nodePath: dataDir,
+        agentServiceHost: '127.0.0.1',
+        clientServiceHost: '127.0.0.1',
+        keys: {
+          passwordOpsLimit: keysUtils.passwordOpsLimits.min,
+          passwordMemLimit: keysUtils.passwordMemLimits.min,
+          strictMemoryLock: false,
+        },
+      },
+      logger: logger,
+    });
+    await polykeyAgent.gestaltGraph.setNode(node1);
+    await polykeyAgent.gestaltGraph.setNode(node2);
+    await polykeyAgent.gestaltGraph.setNode(node3);
+
+    vaultNumber = 0;
+
+    // Authorize session
+    await testUtils.pkStdio(
+      ['agent', 'unlock', '-np', dataDir, '--password-file', passwordFile],
+      {
+        env: {},
+        cwd: dataDir,
+      },
+    );
+    vaultName = genVaultName();
+    command = [];
+  });
+  afterEach(async () => {
+    await polykeyAgent.stop();
+    await fs.promises.rm(dataDir, {
+      force: true,
+      recursive: true,
+    });
+  });
+
+  test('Should get a vaults permissions', async () => {
+    const vaultId1 = await polykeyAgent.vaultManager.createVault(vaultName);
+    const vaultId2 = await polykeyAgent.vaultManager.createVault(
+      vaultName + '1',
+    );
+    const vaultIdEncoded1 = vaultsUtils.encodeVaultId(vaultId1);
+    const vaultIdEncoded2 = vaultsUtils.encodeVaultId(vaultId2);
+    const targetNodeId = nodeIdGenerator();
+    const targetNodeIdEncoded = nodesUtils.encodeNodeId(targetNodeId);
+    await polykeyAgent.gestaltGraph.setNode({
+      nodeId: targetNodeId,
+    });
+
+    // Creating permissions
+    await polykeyAgent.gestaltGraph.setGestaltAction(
+      ['node', targetNodeId],
+      'scan',
+    );
+    await polykeyAgent.acl.setVaultAction(vaultId1, targetNodeId, 'clone');
+    await polykeyAgent.acl.setVaultAction(vaultId1, targetNodeId, 'pull');
+    await polykeyAgent.acl.setVaultAction(vaultId2, targetNodeId, 'pull');
+
+    command = ['vaults', 'permissions', '-np', dataDir, vaultIdEncoded1];
+    const result = await testUtils.pkStdio([...command], {
+      env: {},
+      cwd: dataDir,
+    });
+    expect(result.exitCode).toBe(0);
+    expect(result.stdout).toContain(targetNodeIdEncoded);
+    expect(result.stdout).toContain('clone');
+    expect(result.stdout).toContain('pull');
+
+    command = ['vaults', 'permissions', '-np', dataDir, vaultIdEncoded2];
+    const result2 = await testUtils.pkStdio([...command], {
+      env: {},
+      cwd: dataDir,
+    });
+    expect(result2.exitCode).toBe(0);
+    expect(result2.stdout).toContain(targetNodeIdEncoded);
+    expect(result2.stdout).not.toContain('clone');
+    expect(result2.stdout).toContain('pull');
+  });
+});
diff --git a/tests/vaults/pullClone.test.ts b/tests/vaults/pullClone.test.ts
new file mode 100644
index 00000000..8bca87d7
--- /dev/null
+++ b/tests/vaults/pullClone.test.ts
@@ -0,0 +1,268 @@
+import type { VaultName } from 'polykey/dist/vaults/types';
+import type { GestaltNodeInfo } from 'polykey/dist/gestalts/types';
+import path from 'path';
+import fs from 'fs';
+import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
+import PolykeyAgent from 'polykey/dist/PolykeyAgent';
+import * as ids from 'polykey/dist/ids';
+import * as nodesUtils from 'polykey/dist/nodes/utils';
+import * as vaultsUtils from 'polykey/dist/vaults/utils';
+import sysexits from 'polykey/dist/utils/sysexits';
+import * as keysUtils from 'polykey/dist/keys/utils';
+import * as testUtils from '../utils';
+
+describe('pull and clone', () => {
+  const password = 'password';
+  const logger = new Logger('CLI Test', LogLevel.WARN, [new StreamHandler()]);
+  let dataDir: string;
+  let passwordFile: string;
+  let polykeyAgent: PolykeyAgent;
+  let command: Array<string>;
+  let vaultNumber: number;
+  let vaultName: VaultName;
+  const nodeIdGenerator = ids.createNodeIdGenerator();
+  const nodeId1 = nodeIdGenerator();
+  const nodeId2 = nodeIdGenerator();
+  const nodeId3 = nodeIdGenerator();
+  const node1: GestaltNodeInfo = {
+    nodeId: nodeId1,
+  };
+  const node2: GestaltNodeInfo = {
+    nodeId: nodeId2,
+  };
+  const node3: GestaltNodeInfo = {
+    nodeId: nodeId3,
+  };
+  // Helper functions
+  function genVaultName() {
+    vaultNumber++;
+    return `vault-${vaultNumber}` as VaultName;
+  }
+  beforeEach(async () => {
+    dataDir = await fs.promises.mkdtemp(
+      path.join(globalThis.tmpDir, 'polykey-test-'),
+    );
+    passwordFile = path.join(dataDir, 'passwordFile');
+    await fs.promises.writeFile(passwordFile, 'password');
+    polykeyAgent = await PolykeyAgent.createPolykeyAgent({
+      password,
+      options: {
+        nodePath: dataDir,
+        agentServiceHost: '127.0.0.1',
+        clientServiceHost: '127.0.0.1',
+        keys: {
+          passwordOpsLimit: keysUtils.passwordOpsLimits.min,
+          passwordMemLimit: keysUtils.passwordMemLimits.min,
+          strictMemoryLock: false,
+        },
+      },
+      logger: logger,
+    });
+    await polykeyAgent.gestaltGraph.setNode(node1);
+    await polykeyAgent.gestaltGraph.setNode(node2);
+    await polykeyAgent.gestaltGraph.setNode(node3);
+
+    vaultNumber = 0;
+
+    // Authorize session
+    await testUtils.pkStdio(
+      ['agent', 'unlock', '-np', dataDir, '--password-file', passwordFile],
+      {
+        env: {},
+        cwd: dataDir,
+      },
+    );
+    vaultName = genVaultName();
+    command = [];
+  });
+  afterEach(async () => {
+    await polykeyAgent.stop();
+    await fs.promises.rm(dataDir, {
+      force: true,
+      recursive: true,
+    });
+  });
+
+  test(
+    'should clone and pull a vault',
+    async () => {
+      const dataDir2 = await fs.promises.mkdtemp(
+        path.join(globalThis.tmpDir, 'polykey-test-'),
+      );
+      const targetPolykeyAgent = await PolykeyAgent.createPolykeyAgent({
+        password,
+        options: {
+          nodePath: dataDir2,
+          agentServiceHost: '127.0.0.1',
+          clientServiceHost: '127.0.0.1',
+          keys: {
+            passwordOpsLimit: keysUtils.passwordOpsLimits.min,
+            passwordMemLimit: keysUtils.passwordMemLimits.min,
+            strictMemoryLock: false,
+          },
+        },
+        logger: logger,
+      });
+      const vaultId =
+        await targetPolykeyAgent.vaultManager.createVault(vaultName);
+      await targetPolykeyAgent.vaultManager.withVaults(
+        [vaultId],
+        async (vault) => {
+          await vault.writeF(async (efs) => {
+            await efs.writeFile('secret 1', 'secret the first');
+          });
+        },
+      );
+
+      await targetPolykeyAgent.gestaltGraph.setNode({
+        nodeId: polykeyAgent.keyRing.getNodeId(),
+      });
+      const targetNodeId = targetPolykeyAgent.keyRing.getNodeId();
+      const targetNodeIdEncoded = nodesUtils.encodeNodeId(targetNodeId);
+      await polykeyAgent.nodeManager.setNode(
+        targetNodeId,
+        [
+          targetPolykeyAgent.agentServiceHost,
+          targetPolykeyAgent.agentServicePort,
+        ],
+        {
+          mode: 'direct',
+          connectedTime: Date.now(),
+          scopes: ['global'],
+        },
+      );
+      await targetPolykeyAgent.nodeManager.setNode(
+        polykeyAgent.keyRing.getNodeId(),
+        [polykeyAgent.agentServiceHost, polykeyAgent.agentServicePort],
+        {
+          mode: 'direct',
+          connectedTime: Date.now(),
+          scopes: ['global'],
+        },
+      );
+      await polykeyAgent.acl.setNodePerm(targetNodeId, {
+        gestalt: {
+          notify: null,
+        },
+        vaults: {},
+      });
+
+      const nodeId = polykeyAgent.keyRing.getNodeId();
+      await targetPolykeyAgent.gestaltGraph.setGestaltAction(
+        ['node', nodeId],
+        'scan',
+      );
+      await targetPolykeyAgent.acl.setVaultAction(vaultId, nodeId, 'clone');
+      await targetPolykeyAgent.acl.setVaultAction(vaultId, nodeId, 'pull');
+
+      command = [
+        'vaults',
+        'clone',
+        '-np',
+        dataDir,
+        vaultsUtils.encodeVaultId(vaultId),
+        targetNodeIdEncoded,
+      ];
+
+      let result = await testUtils.pkStdio([...command], {
+        env: {},
+        cwd: dataDir,
+      });
+      expect(result.exitCode).toBe(0);
+
+      const clonedVaultId =
+        await polykeyAgent.vaultManager.getVaultId(vaultName);
+
+      await polykeyAgent.vaultManager.withVaults(
+        [clonedVaultId!],
+        async (clonedVault) => {
+          const file = await clonedVault.readF(async (efs) => {
+            return await efs.readFile('secret 1', { encoding: 'utf8' });
+          });
+          expect(file).toBe('secret the first');
+        },
+      );
+
+      await polykeyAgent.vaultManager.destroyVault(clonedVaultId!);
+      command = [
+        'vaults',
+        'clone',
+        '-np',
+        dataDir,
+        vaultName,
+        nodesUtils.encodeNodeId(targetNodeId),
+      ];
+      result = await testUtils.pkStdio([...command], { env: {}, cwd: dataDir });
+      expect(result.exitCode).toBe(0);
+
+      const secondClonedVaultId =
+        (await polykeyAgent.vaultManager.getVaultId(vaultName))!;
+      await polykeyAgent.vaultManager.withVaults(
+        [secondClonedVaultId!],
+        async (secondClonedVault) => {
+          const file = await secondClonedVault.readF(async (efs) => {
+            return await efs.readFile('secret 1', { encoding: 'utf8' });
+          });
+          expect(file).toBe('secret the first');
+        },
+      );
+
+      await targetPolykeyAgent.vaultManager.withVaults(
+        [vaultId],
+        async (vault) => {
+          await vault.writeF(async (efs) => {
+            await efs.writeFile('secret 2', 'secret the second');
+          });
+        },
+      );
+
+      command = ['vaults', 'pull', '-np', dataDir, vaultName];
+      result = await testUtils.pkStdio([...command], { env: {}, cwd: dataDir });
+      expect(result.exitCode).toBe(0);
+
+      await polykeyAgent.vaultManager.withVaults(
+        [secondClonedVaultId!],
+        async (secondClonedVault) => {
+          const file = await secondClonedVault.readF(async (efs) => {
+            return await efs.readFile('secret 2', { encoding: 'utf8' });
+          });
+          expect(file).toBe('secret the second');
+        },
+      );
+
+      command = [
+        'vaults',
+        'pull',
+        '-np',
+        dataDir,
+        '-pv',
+        'InvalidName',
+        vaultsUtils.encodeVaultId(secondClonedVaultId),
+        targetNodeIdEncoded,
+      ];
+      result = await testUtils.pkStdio([...command], { env: {}, cwd: dataDir });
+      expect(result.exitCode).toBe(sysexits.USAGE);
+      expect(result.stderr).toContain('ErrorVaultsVaultUndefined');
+
+      command = [
+        'vaults',
+        'pull',
+        '-np',
+        dataDir,
+        '-pv',
+        vaultName,
+        vaultsUtils.encodeVaultId(secondClonedVaultId),
+        'InvalidNodeId',
+      ];
+      result = await testUtils.pkStdio([...command], { env: {}, cwd: dataDir });
+      expect(result.exitCode).toBe(sysexits.USAGE);
+
+      await targetPolykeyAgent.stop();
+      await fs.promises.rm(dataDir2, {
+        force: true,
+        recursive: true,
+      });
+    },
+    globalThis.defaultTimeout * 3,
+  );
+});
diff --git a/tests/vaults/rename.test.ts b/tests/vaults/rename.test.ts
new file mode 100644
index 00000000..655cfc9e
--- /dev/null
+++ b/tests/vaults/rename.test.ts
@@ -0,0 +1,130 @@
+import type { VaultName } from 'polykey/dist/vaults/types';
+import type { GestaltNodeInfo } from 'polykey/dist/gestalts/types';
+import path from 'path';
+import fs from 'fs';
+import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
+import PolykeyAgent from 'polykey/dist/PolykeyAgent';
+import * as ids from 'polykey/dist/ids';
+import sysexits from 'polykey/dist/utils/sysexits';
+import * as keysUtils from 'polykey/dist/keys/utils';
+import * as testUtils from '../utils';
+
+describe('commandRenameVault', () => {
+  const password = 'password';
+  const logger = new Logger('CLI Test', LogLevel.WARN, [new StreamHandler()]);
+  let dataDir: string;
+  let passwordFile: string;
+  let polykeyAgent: PolykeyAgent;
+  let command: Array<string>;
+  let vaultNumber: number;
+  let vaultName: VaultName;
+  const nodeIdGenerator = ids.createNodeIdGenerator();
+  const nodeId1 = nodeIdGenerator();
+  const nodeId2 = nodeIdGenerator();
+  const nodeId3 = nodeIdGenerator();
+  const node1: GestaltNodeInfo = {
+    nodeId: nodeId1,
+  };
+  const node2: GestaltNodeInfo = {
+    nodeId: nodeId2,
+  };
+  const node3: GestaltNodeInfo = {
+    nodeId: nodeId3,
+  };
+  // Helper functions
+  function genVaultName() {
+    vaultNumber++;
+    return `vault-${vaultNumber}` as VaultName;
+  }
+  beforeEach(async () => {
+    dataDir = await fs.promises.mkdtemp(
+      path.join(globalThis.tmpDir, 'polykey-test-'),
+    );
+    passwordFile = path.join(dataDir, 'passwordFile');
+    await fs.promises.writeFile(passwordFile, 'password');
+    polykeyAgent = await PolykeyAgent.createPolykeyAgent({
+      password,
+      options: {
+        nodePath: dataDir,
+        agentServiceHost: '127.0.0.1',
+        clientServiceHost: '127.0.0.1',
+        keys: {
+          passwordOpsLimit: keysUtils.passwordOpsLimits.min,
+          passwordMemLimit: keysUtils.passwordMemLimits.min,
+          strictMemoryLock: false,
+        },
+      },
+      logger: logger,
+    });
+    await polykeyAgent.gestaltGraph.setNode(node1);
+    await polykeyAgent.gestaltGraph.setNode(node2);
+    await polykeyAgent.gestaltGraph.setNode(node3);
+
+    vaultNumber = 0;
+
+    // Authorize session
+    await testUtils.pkStdio(
+      ['agent', 'unlock', '-np', dataDir, '--password-file', passwordFile],
+      {
+        env: {},
+        cwd: dataDir,
+      },
+    );
+    vaultName = genVaultName();
+    command = [];
+  });
+  afterEach(async () => {
+    await polykeyAgent.stop();
+    await fs.promises.rm(dataDir, {
+      force: true,
+      recursive: true,
+    });
+  });
+
+  test('should rename vault', async () => {
+    command = ['vaults', 'rename', vaultName, 'RenamedVault', '-np', dataDir];
+    await polykeyAgent.vaultManager.createVault(vaultName);
+    const id = polykeyAgent.vaultManager.getVaultId(vaultName);
+    expect(id).toBeTruthy();
+
+    const result = await testUtils.pkStdio([...command], {
+      env: {},
+      cwd: dataDir,
+    });
+    expect(result.exitCode).toBe(0);
+
+    const list = (await polykeyAgent.vaultManager.listVaults()).keys();
+    const namesList: string[] = [];
+    for await (const name of list) {
+      namesList.push(name);
+    }
+    expect(namesList).toContain('RenamedVault');
+  });
+  test('should fail to rename non-existent vault', async () => {
+    command = [
+      'vaults',
+      'rename',
+      'z4iAXFwgHGeyUrdC5CiCNU4', // Vault does not exist
+      'RenamedVault',
+      '-np',
+      dataDir,
+    ];
+    await polykeyAgent.vaultManager.createVault(vaultName);
+    const id = polykeyAgent.vaultManager.getVaultId(vaultName);
+    expect(id).toBeTruthy();
+
+    const result = await testUtils.pkStdio([...command], {
+      env: {},
+      cwd: dataDir,
+    });
+    // Exit code of the exception
+    expect(result.exitCode).toBe(sysexits.USAGE);
+
+    const list = (await polykeyAgent.vaultManager.listVaults()).keys();
+    const namesList: string[] = [];
+    for await (const name of list) {
+      namesList.push(name);
+    }
+    expect(namesList).toContain(vaultName);
+  });
+});
diff --git a/tests/vaults/scanNode.test.ts b/tests/vaults/scanNode.test.ts
new file mode 100644
index 00000000..59236dfe
--- /dev/null
+++ b/tests/vaults/scanNode.test.ts
@@ -0,0 +1,197 @@
+import type { VaultName } from 'polykey/dist/vaults/types';
+import type { GestaltNodeInfo } from 'polykey/dist/gestalts/types';
+import path from 'path';
+import fs from 'fs';
+import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
+import PolykeyAgent from 'polykey/dist/PolykeyAgent';
+import * as ids from 'polykey/dist/ids';
+import * as nodesUtils from 'polykey/dist/nodes/utils';
+import * as vaultsUtils from 'polykey/dist/vaults/utils';
+import sysexits from 'polykey/dist/utils/sysexits';
+import * as keysUtils from 'polykey/dist/keys/utils';
+import * as testUtils from '../utils';
+
+// Fixme: temperamental problem with formatting the output. Fails sometimes due to an added space
+describe('commandScanNode', () => {
+  const password = 'password';
+  const logger = new Logger('CLI Test', LogLevel.WARN, [new StreamHandler()]);
+  let dataDir: string;
+  let passwordFile: string;
+  let polykeyAgent: PolykeyAgent;
+  const nodeIdGenerator = ids.createNodeIdGenerator();
+  const nodeId1 = nodeIdGenerator();
+  const nodeId2 = nodeIdGenerator();
+  const nodeId3 = nodeIdGenerator();
+  const node1: GestaltNodeInfo = {
+    nodeId: nodeId1,
+  };
+  const node2: GestaltNodeInfo = {
+    nodeId: nodeId2,
+  };
+  const node3: GestaltNodeInfo = {
+    nodeId: nodeId3,
+  };
+  beforeEach(async () => {
+    dataDir = await fs.promises.mkdtemp(
+      path.join(globalThis.tmpDir, 'polykey-test-'),
+    );
+    passwordFile = path.join(dataDir, 'passwordFile');
+    await fs.promises.writeFile(passwordFile, 'password');
+    polykeyAgent = await PolykeyAgent.createPolykeyAgent({
+      password,
+      options: {
+        nodePath: dataDir,
+        agentServiceHost: '127.0.0.1',
+        clientServiceHost: '127.0.0.1',
+        keys: {
+          passwordOpsLimit: keysUtils.passwordOpsLimits.min,
+          passwordMemLimit: keysUtils.passwordMemLimits.min,
+          strictMemoryLock: false,
+        },
+      },
+      logger: logger,
+    });
+    await polykeyAgent.gestaltGraph.setNode(node1);
+    await polykeyAgent.gestaltGraph.setNode(node2);
+    await polykeyAgent.gestaltGraph.setNode(node3);
+
+    // Authorize session
+    await testUtils.pkStdio(
+      ['agent', 'unlock', '-np', dataDir, '--password-file', passwordFile],
+      {
+        env: {},
+        cwd: dataDir,
+      },
+    );
+  });
+  afterEach(async () => {
+    await polykeyAgent.stop();
+    await fs.promises.rm(dataDir, {
+      force: true,
+      recursive: true,
+    });
+  });
+
+  test(
+    'should return the vaults names and ids of the remote vault',
+    async () => {
+      let remoteOnline: PolykeyAgent | undefined;
+      try {
+        remoteOnline = await PolykeyAgent.createPolykeyAgent({
+          password,
+          options: {
+            nodePath: path.join(dataDir, 'remoteOnline'),
+            agentServiceHost: '127.0.0.1',
+            clientServiceHost: '127.0.0.1',
+            keys: {
+              passwordOpsLimit: keysUtils.passwordOpsLimits.min,
+              passwordMemLimit: keysUtils.passwordMemLimits.min,
+              strictMemoryLock: false,
+            },
+          },
+          logger,
+        });
+        const remoteOnlineNodeId = remoteOnline.keyRing.getNodeId();
+        const remoteOnlineNodeIdEncoded =
+          nodesUtils.encodeNodeId(remoteOnlineNodeId);
+        await polykeyAgent.nodeManager.setNode(
+          remoteOnlineNodeId,
+          [remoteOnline.agentServiceHost, remoteOnline.agentServicePort],
+          {
+            mode: 'direct',
+            connectedTime: Date.now(),
+            scopes: ['global'],
+          },
+        );
+
+        await remoteOnline.gestaltGraph.setNode({
+          nodeId: polykeyAgent.keyRing.getNodeId(),
+        });
+
+        const commands1 = [
+          'vaults',
+          'scan',
+          remoteOnlineNodeIdEncoded,
+          '-np',
+          dataDir,
+        ];
+        const result1 = await testUtils.pkStdio(commands1, {
+          env: { PK_PASSWORD: 'password' },
+          cwd: dataDir,
+        });
+        expect(result1.exitCode).toEqual(sysexits.NOPERM);
+        expect(result1.stderr).toContain(
+          'ErrorVaultsPermissionDenied: Permission was denied - Scanning is not allowed for',
+        );
+
+        await remoteOnline.gestaltGraph.setGestaltAction(
+          ['node', polykeyAgent.keyRing.getNodeId()],
+          'notify',
+        );
+
+        const commands2 = [
+          'vaults',
+          'scan',
+          remoteOnlineNodeIdEncoded,
+          '-np',
+          dataDir,
+        ];
+        const result2 = await testUtils.pkStdio(commands2, {
+          env: { PK_PASSWORD: 'password' },
+          cwd: dataDir,
+        });
+        expect(result2.exitCode).toEqual(sysexits.NOPERM);
+        expect(result2.stderr).toContain(
+          'ErrorVaultsPermissionDenied: Permission was denied - Scanning is not allowed for',
+        );
+
+        await remoteOnline.gestaltGraph.setGestaltAction(
+          ['node', polykeyAgent.keyRing.getNodeId()],
+          'scan',
+        );
+
+        const vault1Id = await remoteOnline.vaultManager.createVault(
+          'Vault1' as VaultName,
+        );
+        const vault2Id = await remoteOnline.vaultManager.createVault(
+          'Vault2' as VaultName,
+        );
+        const vault3Id = await remoteOnline.vaultManager.createVault(
+          'Vault3' as VaultName,
+        );
+        const nodeId = polykeyAgent.keyRing.getNodeId();
+        await remoteOnline.acl.setVaultAction(vault1Id, nodeId, 'clone');
+        await remoteOnline.acl.setVaultAction(vault2Id, nodeId, 'pull');
+        await remoteOnline.acl.setVaultAction(vault2Id, nodeId, 'clone');
+        const commands3 = [
+          'vaults',
+          'scan',
+          remoteOnlineNodeIdEncoded,
+          '-np',
+          dataDir,
+        ];
+        const result3 = await testUtils.pkStdio(commands3, {
+          env: { PK_PASSWORD: 'password' },
+          cwd: dataDir,
+        });
+        expect(result3.exitCode).toBe(0);
+        expect(result3.stdout).toMatch(/Vault1\t.*\tclone/);
+        expect(JSON.stringify(result3.stdout)).toContain(
+          JSON.stringify(
+            `Vault1\t${vaultsUtils.encodeVaultId(
+              vault1Id,
+            )}\tclone\nVault2\t${vaultsUtils.encodeVaultId(
+              vault2Id,
+            )}\tpull,clone\n`,
+          ),
+        );
+        expect(result3.stdout).not.toContain(
+          `Vault3\t${vaultsUtils.encodeVaultId(vault3Id)}`,
+        );
+      } finally {
+        await remoteOnline?.stop();
+      }
+    },
+    globalThis.defaultTimeout * 2,
+  );
+});
diff --git a/tests/vaults/share.test.ts b/tests/vaults/share.test.ts
new file mode 100644
index 00000000..c7e9f04f
--- /dev/null
+++ b/tests/vaults/share.test.ts
@@ -0,0 +1,129 @@
+import type { VaultName } from 'polykey/dist/vaults/types';
+import type { GestaltNodeInfo } from 'polykey/dist/gestalts/types';
+import path from 'path';
+import fs from 'fs';
+import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
+import PolykeyAgent from 'polykey/dist/PolykeyAgent';
+import * as ids from 'polykey/dist/ids';
+import * as nodesUtils from 'polykey/dist/nodes/utils';
+import * as vaultsUtils from 'polykey/dist/vaults/utils';
+import NotificationsManager from 'polykey/dist/notifications/NotificationsManager';
+import * as keysUtils from 'polykey/dist/keys/utils';
+import * as testUtils from '../utils';
+
+describe('commandShare', () => {
+  const password = 'password';
+  const logger = new Logger('CLI Test', LogLevel.WARN, [new StreamHandler()]);
+  let dataDir: string;
+  let passwordFile: string;
+  let polykeyAgent: PolykeyAgent;
+  let command: Array<string>;
+  let vaultNumber: number;
+  let vaultName: VaultName;
+  const nodeIdGenerator = ids.createNodeIdGenerator();
+  const nodeId1 = nodeIdGenerator();
+  const nodeId2 = nodeIdGenerator();
+  const nodeId3 = nodeIdGenerator();
+  const node1: GestaltNodeInfo = {
+    nodeId: nodeId1,
+  };
+  const node2: GestaltNodeInfo = {
+    nodeId: nodeId2,
+  };
+  const node3: GestaltNodeInfo = {
+    nodeId: nodeId3,
+  };
+  // Helper functions
+  function genVaultName() {
+    vaultNumber++;
+    return `vault-${vaultNumber}` as VaultName;
+  }
+  beforeEach(async () => {
+    dataDir = await fs.promises.mkdtemp(
+      path.join(globalThis.tmpDir, 'polykey-test-'),
+    );
+    passwordFile = path.join(dataDir, 'passwordFile');
+    await fs.promises.writeFile(passwordFile, 'password');
+    polykeyAgent = await PolykeyAgent.createPolykeyAgent({
+      password,
+      options: {
+        nodePath: dataDir,
+        agentServiceHost: '127.0.0.1',
+        clientServiceHost: '127.0.0.1',
+        keys: {
+          passwordOpsLimit: keysUtils.passwordOpsLimits.min,
+          passwordMemLimit: keysUtils.passwordMemLimits.min,
+          strictMemoryLock: false,
+        },
+      },
+      logger: logger,
+    });
+    await polykeyAgent.gestaltGraph.setNode(node1);
+    await polykeyAgent.gestaltGraph.setNode(node2);
+    await polykeyAgent.gestaltGraph.setNode(node3);
+
+    vaultNumber = 0;
+
+    // Authorize session
+    await testUtils.pkStdio(
+      ['agent', 'unlock', '-np', dataDir, '--password-file', passwordFile],
+      {
+        env: {},
+        cwd: dataDir,
+      },
+    );
+    vaultName = genVaultName();
+    command = [];
+  });
+  afterEach(async () => {
+    await polykeyAgent.stop();
+    await fs.promises.rm(dataDir, {
+      force: true,
+      recursive: true,
+    });
+  });
+
+  test('Should share a vault', async () => {
+    const mockedSendNotification = jest.spyOn(
+      NotificationsManager.prototype,
+      'sendNotification',
+    );
+    try {
+      // We don't want to actually send a notification
+      mockedSendNotification.mockImplementation(async (_) => {});
+      const vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
+      const vaultIdEncoded = vaultsUtils.encodeVaultId(vaultId);
+      const targetNodeId = nodeIdGenerator();
+      const targetNodeIdEncoded = nodesUtils.encodeNodeId(targetNodeId);
+      await polykeyAgent.gestaltGraph.setNode({
+        nodeId: targetNodeId,
+      });
+      expect(
+        (await polykeyAgent.acl.getNodePerm(targetNodeId))?.vaults[vaultId],
+      ).toBeUndefined();
+
+      command = [
+        'vaults',
+        'share',
+        '-np',
+        dataDir,
+        vaultIdEncoded,
+        targetNodeIdEncoded,
+      ];
+      const result = await testUtils.pkStdio([...command], {
+        env: {},
+        cwd: dataDir,
+      });
+      expect(result.exitCode).toBe(0);
+
+      // Check permission
+      const permissions1 = (await polykeyAgent.acl.getNodePerm(targetNodeId))
+        ?.vaults[vaultId];
+      expect(permissions1).toBeDefined();
+      expect(permissions1.pull).toBeDefined();
+      expect(permissions1.clone).toBeDefined();
+    } finally {
+      mockedSendNotification.mockRestore();
+    }
+  });
+});
diff --git a/tests/vaults/unshare.test.ts b/tests/vaults/unshare.test.ts
new file mode 100644
index 00000000..67fc5f38
--- /dev/null
+++ b/tests/vaults/unshare.test.ts
@@ -0,0 +1,159 @@
+import type { VaultName } from 'polykey/dist/vaults/types';
+import type { GestaltNodeInfo } from 'polykey/dist/gestalts/types';
+import path from 'path';
+import fs from 'fs';
+import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
+import PolykeyAgent from 'polykey/dist/PolykeyAgent';
+import * as ids from 'polykey/dist/ids';
+import * as nodesUtils from 'polykey/dist/nodes/utils';
+import * as vaultsUtils from 'polykey/dist/vaults/utils';
+import * as keysUtils from 'polykey/dist/keys/utils';
+import * as testUtils from '../utils';
+
+describe('commandUnshare', () => {
+  const password = 'password';
+  const logger = new Logger('CLI Test', LogLevel.WARN, [new StreamHandler()]);
+  let dataDir: string;
+  let passwordFile: string;
+  let polykeyAgent: PolykeyAgent;
+  let command: Array<string>;
+  let vaultNumber: number;
+  let vaultName: VaultName;
+  const nodeIdGenerator = ids.createNodeIdGenerator();
+  const nodeId1 = nodeIdGenerator();
+  const nodeId2 = nodeIdGenerator();
+  const nodeId3 = nodeIdGenerator();
+  const node1: GestaltNodeInfo = {
+    nodeId: nodeId1,
+  };
+  const node2: GestaltNodeInfo = {
+    nodeId: nodeId2,
+  };
+  const node3: GestaltNodeInfo = {
+    nodeId: nodeId3,
+  };
+  // Helper functions
+  function genVaultName() {
+    vaultNumber++;
+    return `vault-${vaultNumber}` as VaultName;
+  }
+  beforeEach(async () => {
+    dataDir = await fs.promises.mkdtemp(
+      path.join(globalThis.tmpDir, 'polykey-test-'),
+    );
+    passwordFile = path.join(dataDir, 'passwordFile');
+    await fs.promises.writeFile(passwordFile, 'password');
+    polykeyAgent = await PolykeyAgent.createPolykeyAgent({
+      password,
+      options: {
+        nodePath: dataDir,
+        agentServiceHost: '127.0.0.1',
+        clientServiceHost: '127.0.0.1',
+        keys: {
+          passwordOpsLimit: keysUtils.passwordOpsLimits.min,
+          passwordMemLimit: keysUtils.passwordMemLimits.min,
+          strictMemoryLock: false,
+        },
+      },
+      logger: logger,
+    });
+    await polykeyAgent.gestaltGraph.setNode(node1);
+    await polykeyAgent.gestaltGraph.setNode(node2);
+    await polykeyAgent.gestaltGraph.setNode(node3);
+
+    vaultNumber = 0;
+
+    // Authorize session
+    await testUtils.pkStdio(
+      ['agent', 'unlock', '-np', dataDir, '--password-file', passwordFile],
+      {
+        env: {},
+        cwd: dataDir,
+      },
+    );
+    vaultName = genVaultName();
+    command = [];
+  });
+  afterEach(async () => {
+    await polykeyAgent.stop();
+    await fs.promises.rm(dataDir, {
+      force: true,
+      recursive: true,
+    });
+  });
+
+  test('Should unshare a vault', async () => {
+    const vaultId1 = await polykeyAgent.vaultManager.createVault(vaultName);
+    const vaultId2 = await polykeyAgent.vaultManager.createVault(
+      vaultName + '1',
+    );
+    const vaultIdEncoded1 = vaultsUtils.encodeVaultId(vaultId1);
+    const vaultIdEncoded2 = vaultsUtils.encodeVaultId(vaultId2);
+    const targetNodeId = nodeIdGenerator();
+    const targetNodeIdEncoded = nodesUtils.encodeNodeId(targetNodeId);
+    await polykeyAgent.gestaltGraph.setNode({
+      nodeId: targetNodeId,
+    });
+
+    // Creating permissions
+    await polykeyAgent.gestaltGraph.setGestaltAction(
+      ['node', targetNodeId],
+      'scan',
+    );
+    await polykeyAgent.acl.setVaultAction(vaultId1, targetNodeId, 'clone');
+    await polykeyAgent.acl.setVaultAction(vaultId1, targetNodeId, 'pull');
+    await polykeyAgent.acl.setVaultAction(vaultId2, targetNodeId, 'clone');
+    await polykeyAgent.acl.setVaultAction(vaultId2, targetNodeId, 'pull');
+
+    command = [
+      'vaults',
+      'unshare',
+      '-np',
+      dataDir,
+      vaultIdEncoded1,
+      targetNodeIdEncoded,
+    ];
+    const result = await testUtils.pkStdio([...command], {
+      env: {},
+      cwd: dataDir,
+    });
+    expect(result.exitCode).toBe(0);
+
+    // Check permission
+    const permissions = (await polykeyAgent.acl.getNodePerm(targetNodeId))
+      ?.vaults[vaultId1];
+    expect(permissions).toBeDefined();
+    expect(permissions.pull).toBeUndefined();
+    expect(permissions.clone).toBeUndefined();
+
+    expect(
+      (await polykeyAgent.acl.getNodePerm(targetNodeId))?.gestalt['scan'],
+    ).toBeDefined();
+
+    command = [
+      'vaults',
+      'unshare',
+      '-np',
+      dataDir,
+      vaultIdEncoded2,
+      targetNodeIdEncoded,
+    ];
+    const result2 = await testUtils.pkStdio([...command], {
+      env: {},
+      cwd: dataDir,
+    });
+    expect(result2.exitCode).toBe(0);
+
+    // Check permission
+    const permissions2 = (await polykeyAgent.acl.getNodePerm(targetNodeId))
+      ?.vaults[vaultId2];
+    expect(permissions2).toBeDefined();
+    expect(permissions2.pull).toBeUndefined();
+    expect(permissions2.clone).toBeUndefined();
+
+    // And the scan permission should be removed
+    expect(
+      (await polykeyAgent.acl.getNodePerm(targetNodeId))?.gestalt['scan'],
+    ).toBeUndefined();
+  });
+});
diff --git a/tests/vaults/vaults.test.ts b/tests/vaults/vaults.test.ts
deleted file mode 100644
index d5639d9c..00000000
--- a/tests/vaults/vaults.test.ts
+++ /dev/null
@@ -1,869 +0,0 @@
-import type { VaultId, VaultName } from 'polykey/dist/vaults/types';
-import type { GestaltNodeInfo } from 'polykey/dist/gestalts/types';
-import path from 'path';
-import fs from 'fs';
-import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
-import PolykeyAgent from 'polykey/dist/PolykeyAgent';
-import * as ids from 'polykey/dist/ids';
-import * as nodesUtils from 'polykey/dist/nodes/utils';
-import * as vaultsUtils from 'polykey/dist/vaults/utils';
-import sysexits from 'polykey/dist/utils/sysexits';
-import NotificationsManager from 'polykey/dist/notifications/NotificationsManager';
-import * as keysUtils from 'polykey/dist/keys/utils';
-import * as testUtils from '../utils';
-
-describe('CLI vaults', () => {
-  const password = 'password';
-  const logger = new Logger('CLI Test', LogLevel.WARN, [new StreamHandler()]);
-  let dataDir: string;
-  let passwordFile: string;
-  let polykeyAgent: PolykeyAgent;
-  let command: Array<string>;
-  let vaultNumber: number;
-  let vaultName: VaultName;
-  const nodeIdGenerator = ids.createNodeIdGenerator();
-  const nodeId1 = nodeIdGenerator();
-  const nodeId2 = nodeIdGenerator();
-  const nodeId3 = nodeIdGenerator();
-  const node1: GestaltNodeInfo = {
-    nodeId: nodeId1,
-  };
-  const node2: GestaltNodeInfo = {
-    nodeId: nodeId2,
-  };
-  const node3: GestaltNodeInfo = {
-    nodeId: nodeId3,
-  };
-  // Helper functions
-  function genVaultName() {
-    vaultNumber++;
-    return `vault-${vaultNumber}` as VaultName;
-  }
-  beforeEach(async () => {
-    dataDir = await fs.promises.mkdtemp(
-      path.join(globalThis.tmpDir, 'polykey-test-'),
-    );
-    passwordFile = path.join(dataDir, 'passwordFile');
-    await fs.promises.writeFile(passwordFile, 'password');
-    polykeyAgent = await PolykeyAgent.createPolykeyAgent({
-      password,
-      options: {
-        nodePath: dataDir,
-        agentServiceHost: '127.0.0.1',
-        clientServiceHost: '127.0.0.1',
-        keys: {
-          passwordOpsLimit: keysUtils.passwordOpsLimits.min,
-          passwordMemLimit: keysUtils.passwordMemLimits.min,
-          strictMemoryLock: false,
-        },
-      },
-      logger: logger,
-    });
-    await polykeyAgent.gestaltGraph.setNode(node1);
-    await polykeyAgent.gestaltGraph.setNode(node2);
-    await polykeyAgent.gestaltGraph.setNode(node3);
-
-    vaultNumber = 0;
-
-    // Authorize session
-    await testUtils.pkStdio(
-      ['agent', 'unlock', '-np', dataDir, '--password-file', passwordFile],
-      {
-        env: {},
-        cwd: dataDir,
-      },
-    );
-    vaultName = genVaultName();
-    command = [];
-  });
-  afterEach(async () => {
-    await polykeyAgent.stop();
-    await fs.promises.rm(dataDir, {
-      force: true,
-      recursive: true,
-    });
-  });
-
-  describe('commandListVaults', () => {
-    test('should list all vaults', async () => {
-      command = ['vaults', 'list', '-np', dataDir];
-      await polykeyAgent.vaultManager.createVault('Vault1' as VaultName);
-      await polykeyAgent.vaultManager.createVault('Vault2' as VaultName);
-
-      const result = await testUtils.pkStdio([...command], {
-        env: {},
-        cwd: dataDir,
-      });
-      expect(result.exitCode).toBe(0);
-    });
-  });
-  describe('commandCreateVaults', () => {
-    test('should create vaults', async () => {
-      command = ['vaults', 'create', '-np', dataDir, 'MyTestVault'];
-      const result = await testUtils.pkStdio([...command], {
-        env: {},
-        cwd: dataDir,
-      });
-      expect(result.exitCode).toBe(0);
-      const result2 = await testUtils.pkStdio(
-        ['vaults', 'touch', '-np', dataDir, 'MyTestVault2'],
-        {
-          env: {},
-          cwd: dataDir,
-        },
-      );
-      expect(result2.exitCode).toBe(0);
-
-      const list = (await polykeyAgent.vaultManager.listVaults()).keys();
-      const namesList: string[] = [];
-      for await (const name of list) {
-        namesList.push(name);
-      }
-      expect(namesList).toContain('MyTestVault');
-      expect(namesList).toContain('MyTestVault2');
-    });
-  });
-  describe('commandRenameVault', () => {
-    test('should rename vault', async () => {
-      command = ['vaults', 'rename', vaultName, 'RenamedVault', '-np', dataDir];
-      await polykeyAgent.vaultManager.createVault(vaultName);
-      const id = polykeyAgent.vaultManager.getVaultId(vaultName);
-      expect(id).toBeTruthy();
-
-      const result = await testUtils.pkStdio([...command], {
-        env: {},
-        cwd: dataDir,
-      });
-      expect(result.exitCode).toBe(0);
-
-      const list = (await polykeyAgent.vaultManager.listVaults()).keys();
-      const namesList: string[] = [];
-      for await (const name of list) {
-        namesList.push(name);
-      }
-      expect(namesList).toContain('RenamedVault');
-    });
-    test('should fail to rename non-existent vault', async () => {
-      command = [
-        'vaults',
-        'rename',
-        'z4iAXFwgHGeyUrdC5CiCNU4', // Vault does not exist
-        'RenamedVault',
-        '-np',
-        dataDir,
-      ];
-      await polykeyAgent.vaultManager.createVault(vaultName);
-      const id = polykeyAgent.vaultManager.getVaultId(vaultName);
-      expect(id).toBeTruthy();
-
-      const result = await testUtils.pkStdio([...command], {
-        env: {},
-        cwd: dataDir,
-      });
-      // Exit code of the exception
-      expect(result.exitCode).toBe(sysexits.USAGE);
-
-      const list = (await polykeyAgent.vaultManager.listVaults()).keys();
-      const namesList: string[] = [];
-      for await (const name of list) {
-        namesList.push(name);
-      }
-      expect(namesList).toContain(vaultName);
-    });
-  });
-  describe('commandDeleteVault', () => {
-    test('should delete vault', async () => {
-      command = ['vaults', 'delete', '-np', dataDir, vaultName];
-      await polykeyAgent.vaultManager.createVault(vaultName);
-      let id = polykeyAgent.vaultManager.getVaultId(vaultName);
-      expect(id).toBeTruthy();
-
-      id = polykeyAgent.vaultManager.getVaultId(vaultName);
-      expect(id).toBeTruthy();
-
-      const result2 = await testUtils.pkStdio([...command], {
-        env: {},
-        cwd: dataDir,
-      });
-      expect(result2.exitCode).toBe(0);
-
-      const list = (await polykeyAgent.vaultManager.listVaults()).keys();
-      const namesList: string[] = [];
-      for await (const name of list) {
-        namesList.push(name);
-      }
-      expect(namesList).not.toContain(vaultName);
-    });
-  });
-  test(
-    'should clone and pull a vault',
-    async () => {
-      const dataDir2 = await fs.promises.mkdtemp(
-        path.join(globalThis.tmpDir, 'polykey-test-'),
-      );
-      const targetPolykeyAgent = await PolykeyAgent.createPolykeyAgent({
-        password,
-        options: {
-          nodePath: dataDir2,
-          agentServiceHost: '127.0.0.1',
-          clientServiceHost: '127.0.0.1',
-          keys: {
-            passwordOpsLimit: keysUtils.passwordOpsLimits.min,
-            passwordMemLimit: keysUtils.passwordMemLimits.min,
-            strictMemoryLock: false,
-          },
-        },
-        logger: logger,
-      });
-      const vaultId =
-        await targetPolykeyAgent.vaultManager.createVault(vaultName);
-      await targetPolykeyAgent.vaultManager.withVaults(
-        [vaultId],
-        async (vault) => {
-          await vault.writeF(async (efs) => {
-            await efs.writeFile('secret 1', 'secret the first');
-          });
-        },
-      );
-
-      await targetPolykeyAgent.gestaltGraph.setNode({
-        nodeId: polykeyAgent.keyRing.getNodeId(),
-      });
-      const targetNodeId = targetPolykeyAgent.keyRing.getNodeId();
-      const targetNodeIdEncoded = nodesUtils.encodeNodeId(targetNodeId);
-      await polykeyAgent.nodeManager.setNode(
-        targetNodeId,
-        [
-          targetPolykeyAgent.agentServiceHost,
-          targetPolykeyAgent.agentServicePort,
-        ],
-        {
-          mode: 'direct',
-          connectedTime: Date.now(),
-          scopes: ['global'],
-        },
-      );
-      await targetPolykeyAgent.nodeManager.setNode(
-        polykeyAgent.keyRing.getNodeId(),
-        [polykeyAgent.agentServiceHost, polykeyAgent.agentServicePort],
-        {
-          mode: 'direct',
-          connectedTime: Date.now(),
-          scopes: ['global'],
-        },
-      );
-      await polykeyAgent.acl.setNodePerm(targetNodeId, {
-        gestalt: {
-          notify: null,
-        },
-        vaults: {},
-      });
-
-      const nodeId = polykeyAgent.keyRing.getNodeId();
-      await targetPolykeyAgent.gestaltGraph.setGestaltAction(
-        ['node', nodeId],
-        'scan',
-      );
-      await targetPolykeyAgent.acl.setVaultAction(vaultId, nodeId, 'clone');
-      await targetPolykeyAgent.acl.setVaultAction(vaultId, nodeId, 'pull');
-
-      command = [
-        'vaults',
-        'clone',
-        '-np',
-        dataDir,
-        vaultsUtils.encodeVaultId(vaultId),
-        targetNodeIdEncoded,
-      ];
-
-      let result = await testUtils.pkStdio([...command], {
-        env: {},
-        cwd: dataDir,
-      });
-      expect(result.exitCode).toBe(0);
-
-      const clonedVaultId =
-        await polykeyAgent.vaultManager.getVaultId(vaultName);
-
-      await polykeyAgent.vaultManager.withVaults(
-        [clonedVaultId!],
-        async (clonedVault) => {
-          const file = await clonedVault.readF(async (efs) => {
-            return await efs.readFile('secret 1', { encoding: 'utf8' });
-          });
-          expect(file).toBe('secret the first');
-        },
-      );
-
-      await polykeyAgent.vaultManager.destroyVault(clonedVaultId!);
-      command = [
-        'vaults',
-        'clone',
-        '-np',
-        dataDir,
-        vaultName,
-        nodesUtils.encodeNodeId(targetNodeId),
-      ];
-      result = await testUtils.pkStdio([...command], { env: {}, cwd: dataDir });
-      expect(result.exitCode).toBe(0);
-
-      const secondClonedVaultId =
-        (await polykeyAgent.vaultManager.getVaultId(vaultName))!;
-      await polykeyAgent.vaultManager.withVaults(
-        [secondClonedVaultId!],
-        async (secondClonedVault) => {
-          const file = await secondClonedVault.readF(async (efs) => {
-            return await efs.readFile('secret 1', { encoding: 'utf8' });
-          });
-          expect(file).toBe('secret the first');
-        },
-      );
-
-      await targetPolykeyAgent.vaultManager.withVaults(
-        [vaultId],
-        async (vault) => {
-          await vault.writeF(async (efs) => {
-            await efs.writeFile('secret 2', 'secret the second');
-          });
-        },
-      );
-
-      command = ['vaults', 'pull', '-np', dataDir, vaultName];
-      result = await testUtils.pkStdio([...command], { env: {}, cwd: dataDir });
-      expect(result.exitCode).toBe(0);
-
-      await polykeyAgent.vaultManager.withVaults(
-        [secondClonedVaultId!],
-        async (secondClonedVault) => {
-          const file = await secondClonedVault.readF(async (efs) => {
-            return await efs.readFile('secret 2', { encoding: 'utf8' });
-          });
-          expect(file).toBe('secret the second');
-        },
-      );
-
-      command = [
-        'vaults',
-        'pull',
-        '-np',
-        dataDir,
-        '-pv',
-        'InvalidName',
-        vaultsUtils.encodeVaultId(secondClonedVaultId),
-        targetNodeIdEncoded,
-      ];
-      result = await testUtils.pkStdio([...command], { env: {}, cwd: dataDir });
-      expect(result.exitCode).toBe(sysexits.USAGE);
-      expect(result.stderr).toContain('ErrorVaultsVaultUndefined');
-
-      command = [
-        'vaults',
-        'pull',
-        '-np',
-        dataDir,
-        '-pv',
-        vaultName,
-        vaultsUtils.encodeVaultId(secondClonedVaultId),
-        'InvalidNodeId',
-      ];
-      result = await testUtils.pkStdio([...command], { env: {}, cwd: dataDir });
-      expect(result.exitCode).toBe(sysexits.USAGE);
-
-      await targetPolykeyAgent.stop();
-      await fs.promises.rm(dataDir2, {
-        force: true,
-        recursive: true,
-      });
-    },
-    globalThis.defaultTimeout * 3,
-  );
-  describe('commandShare', () => {
-    test('Should share a vault', async () => {
-      const mockedSendNotification = jest.spyOn(
-        NotificationsManager.prototype,
-        'sendNotification',
-      );
-      try {
-        // We don't want to actually send a notification
-        mockedSendNotification.mockImplementation(async (_) => {});
-        const vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
-        const vaultIdEncoded = vaultsUtils.encodeVaultId(vaultId);
-        const targetNodeId = nodeIdGenerator();
-        const targetNodeIdEncoded = nodesUtils.encodeNodeId(targetNodeId);
-        await polykeyAgent.gestaltGraph.setNode({
-          nodeId: targetNodeId,
-        });
-        expect(
-          (await polykeyAgent.acl.getNodePerm(targetNodeId))?.vaults[vaultId],
-        ).toBeUndefined();
-
-        command = [
-          'vaults',
-          'share',
-          '-np',
-          dataDir,
-          vaultIdEncoded,
-          targetNodeIdEncoded,
-        ];
-        const result = await testUtils.pkStdio([...command], {
-          env: {},
-          cwd: dataDir,
-        });
-        expect(result.exitCode).toBe(0);
-
-        // Check permission
-        const permissions1 = (await polykeyAgent.acl.getNodePerm(targetNodeId))
-          ?.vaults[vaultId];
-        expect(permissions1).toBeDefined();
-        expect(permissions1.pull).toBeDefined();
-        expect(permissions1.clone).toBeDefined();
-      } finally {
-        mockedSendNotification.mockRestore();
-      }
-    });
-  });
-  describe('commandUnshare', () => {
-    test('Should unshare a vault', async () => {
-      const vaultId1 = await polykeyAgent.vaultManager.createVault(vaultName);
-      const vaultId2 = await polykeyAgent.vaultManager.createVault(
-        vaultName + '1',
-      );
-      const vaultIdEncoded1 = vaultsUtils.encodeVaultId(vaultId1);
-      const vaultIdEncoded2 = vaultsUtils.encodeVaultId(vaultId2);
-      const targetNodeId = nodeIdGenerator();
-      const targetNodeIdEncoded = nodesUtils.encodeNodeId(targetNodeId);
-      await polykeyAgent.gestaltGraph.setNode({
-        nodeId: targetNodeId,
-      });
-
-      // Creating permissions
-      await polykeyAgent.gestaltGraph.setGestaltAction(
-        ['node', targetNodeId],
-        'scan',
-      );
-      await polykeyAgent.acl.setVaultAction(vaultId1, targetNodeId, 'clone');
-      await polykeyAgent.acl.setVaultAction(vaultId1, targetNodeId, 'pull');
-      await polykeyAgent.acl.setVaultAction(vaultId2, targetNodeId, 'clone');
-      await polykeyAgent.acl.setVaultAction(vaultId2, targetNodeId, 'pull');
-
-      command = [
-        'vaults',
-        'unshare',
-        '-np',
-        dataDir,
-        vaultIdEncoded1,
-        targetNodeIdEncoded,
-      ];
-      const result = await testUtils.pkStdio([...command], {
-        env: {},
-        cwd: dataDir,
-      });
-      expect(result.exitCode).toBe(0);
-
-      // Check permission
-      const permissions = (await polykeyAgent.acl.getNodePerm(targetNodeId))
-        ?.vaults[vaultId1];
-      expect(permissions).toBeDefined();
-      expect(permissions.pull).toBeUndefined();
-      expect(permissions.clone).toBeUndefined();
-
-      expect(
-        (await polykeyAgent.acl.getNodePerm(targetNodeId))?.gestalt['scan'],
-      ).toBeDefined();
-
-      command = [
-        'vaults',
-        'unshare',
-        '-np',
-        dataDir,
-        vaultIdEncoded2,
-        targetNodeIdEncoded,
-      ];
-      const result2 = await testUtils.pkStdio([...command], {
-        env: {},
-        cwd: dataDir,
-      });
-      expect(result2.exitCode).toBe(0);
-
-      // Check permission
-      const permissions2 = (await polykeyAgent.acl.getNodePerm(targetNodeId))
-        ?.vaults[vaultId2];
-      expect(permissions2).toBeDefined();
-      expect(permissions2.pull).toBeUndefined();
-      expect(permissions2.clone).toBeUndefined();
-
-      // And the scan permission should be removed
-      expect(
-        (await polykeyAgent.acl.getNodePerm(targetNodeId))?.gestalt['scan'],
-      ).toBeUndefined();
-    });
-  });
-  describe('commandPermissions', () => {
-    test('Should get a vaults permissions', async () => {
-      const vaultId1 = await polykeyAgent.vaultManager.createVault(vaultName);
-      const vaultId2 = await polykeyAgent.vaultManager.createVault(
-        vaultName + '1',
-      );
-      const vaultIdEncoded1 = vaultsUtils.encodeVaultId(vaultId1);
-      const vaultIdEncoded2 = vaultsUtils.encodeVaultId(vaultId2);
-      const targetNodeId = nodeIdGenerator();
-      const targetNodeIdEncoded = nodesUtils.encodeNodeId(targetNodeId);
-      await polykeyAgent.gestaltGraph.setNode({
-        nodeId: targetNodeId,
-      });
-
-      // Creating permissions
-      await polykeyAgent.gestaltGraph.setGestaltAction(
-        ['node', targetNodeId],
-        'scan',
-      );
-      await polykeyAgent.acl.setVaultAction(vaultId1, targetNodeId, 'clone');
-      await polykeyAgent.acl.setVaultAction(vaultId1, targetNodeId, 'pull');
-      await polykeyAgent.acl.setVaultAction(vaultId2, targetNodeId, 'pull');
-
-      command = ['vaults', 'permissions', '-np', dataDir, vaultIdEncoded1];
-      const result = await testUtils.pkStdio([...command], {
-        env: {},
-        cwd: dataDir,
-      });
-      expect(result.exitCode).toBe(0);
-      expect(result.stdout).toContain(targetNodeIdEncoded);
-      expect(result.stdout).toContain('clone');
-      expect(result.stdout).toContain('pull');
-
-      command = ['vaults', 'permissions', '-np', dataDir, vaultIdEncoded2];
-      const result2 = await testUtils.pkStdio([...command], {
-        env: {},
-        cwd: dataDir,
-      });
-      expect(result2.exitCode).toBe(0);
-      expect(result2.stdout).toContain(targetNodeIdEncoded);
-      expect(result2.stdout).not.toContain('clone');
-      expect(result2.stdout).toContain('pull');
-    });
-  });
-  describe('commandVaultVersion', () => {
-    test('should switch the version of a vault', async () => {
-      const vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
-      const id = polykeyAgent.vaultManager.getVaultId(vaultName);
-      expect(id).toBeTruthy();
-
-      const secret1 = { name: 'Secret-1', content: 'Secret-1-content' };
-      const secret2 = { name: 'Secret-1', content: 'Secret-2-content' };
-
-      const ver1Oid = await polykeyAgent.vaultManager.withVaults(
-        [vaultId],
-        async (vault) => {
-          await vault.writeF(async (efs) => {
-            await efs.writeFile(secret1.name, secret1.content);
-          });
-          const ver1Oid = (await vault.log(undefined, 1))[0].commitId;
-
-          await vault.writeF(async (efs) => {
-            await efs.writeFile(secret2.name, secret2.content);
-          });
-          return ver1Oid;
-        },
-      );
-
-      const command = ['vaults', 'version', '-np', dataDir, vaultName, ver1Oid];
-
-      const result = await testUtils.pkStdio([...command], {
-        env: {},
-        cwd: dataDir,
-      });
-      expect(result.exitCode).toBe(0);
-
-      await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
-        const fileContents = await vault.readF(async (efs) => {
-          return (await efs.readFile(secret1.name)).toString();
-        });
-        expect(fileContents).toStrictEqual(secret1.content);
-      });
-    });
-    test('should switch the version of a vault to the latest version', async () => {
-      const vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
-      const id = polykeyAgent.vaultManager.getVaultId(vaultName);
-      expect(id).toBeTruthy();
-
-      const secret1 = { name: 'Secret-1', content: 'Secret-1-content' };
-      const secret2 = { name: 'Secret-1', content: 'Secret-2-content' };
-
-      const ver1Oid = await polykeyAgent.vaultManager.withVaults(
-        [vaultId],
-        async (vault) => {
-          await vault.writeF(async (efs) => {
-            await efs.writeFile(secret1.name, secret1.content);
-          });
-          const ver1Oid = (await vault.log(undefined, 1))[0].commitId;
-
-          await vault.writeF(async (efs) => {
-            await efs.writeFile(secret2.name, secret2.content);
-          });
-          return ver1Oid;
-        },
-      );
-
-      const command = ['vaults', 'version', '-np', dataDir, vaultName, ver1Oid];
-
-      const result = await testUtils.pkStdio([...command], {
-        env: {},
-        cwd: dataDir,
-      });
-      expect(result.exitCode).toBe(0);
-
-      const command2 = ['vaults', 'version', '-np', dataDir, vaultName, 'last'];
-
-      const result2 = await testUtils.pkStdio([...command2], {
-        env: {},
-        cwd: dataDir,
-      });
-      expect(result2.exitCode).toBe(0);
-    });
-    test('should handle invalid version IDs', async () => {
-      await polykeyAgent.vaultManager.createVault(vaultName);
-      const id = polykeyAgent.vaultManager.getVaultId(vaultName);
-      expect(id).toBeTruthy();
-
-      const command = [
-        'vaults',
-        'version',
-        '-np',
-        dataDir,
-        vaultName,
-        'NOT_A_VALID_CHECKOUT_ID',
-      ];
-
-      const result = await testUtils.pkStdio([...command], {
-        env: {},
-        cwd: dataDir,
-      });
-      expect(result.exitCode).toBe(sysexits.USAGE);
-
-      expect(result.stderr).toContain('ErrorVaultReferenceInvalid');
-    });
-    test('should throw an error if the vault is not found', async () => {
-      const command = [
-        'vaults',
-        'version',
-        '-np',
-        dataDir,
-        'zLnM7puKobbh4YXEz66StAq',
-        'NOT_A_VALID_CHECKOUT_ID',
-      ];
-
-      const result = await testUtils.pkStdio([...command], {
-        env: {},
-        cwd: dataDir,
-      });
-      expect(result.exitCode).toBe(sysexits.USAGE);
-      expect(result.stderr).toContain('ErrorVaultsVaultUndefined');
-    });
-  });
-  describe('commandVaultLog', () => {
-    const secret1 = { name: 'secret1', content: 'Secret-1-content' };
-    const secret2 = { name: 'secret2', content: 'Secret-2-content' };
-
-    let vaultId: VaultId;
-    let writeF1Oid: string;
-    let writeF2Oid: string;
-    let writeF3Oid: string;
-
-    beforeEach(async () => {
-      vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
-
-      await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
-        await vault.writeF(async (efs) => {
-          await efs.writeFile(secret1.name, secret1.content);
-        });
-        writeF1Oid = (await vault.log(undefined, 0))[0].commitId;
-
-        await vault.writeF(async (efs) => {
-          await efs.writeFile(secret2.name, secret2.content);
-        });
-        writeF2Oid = (await vault.log(undefined, 0))[0].commitId;
-
-        await vault.writeF(async (efs) => {
-          await efs.unlink(secret2.name);
-        });
-        writeF3Oid = (await vault.log(undefined, 0))[0].commitId;
-      });
-    });
-    afterEach(async () => {
-      await polykeyAgent.vaultManager.destroyVault(vaultId);
-    });
-
-    test('Should get all writeFs', async () => {
-      const command = ['vaults', 'log', '-np', dataDir, vaultName];
-
-      const result = await testUtils.pkStdio([...command], {
-        env: {},
-        cwd: dataDir,
-      });
-      expect(result.exitCode).toEqual(0);
-      expect(result.stdout).toContain(writeF1Oid);
-      expect(result.stdout).toContain(writeF2Oid);
-      expect(result.stdout).toContain(writeF3Oid);
-    });
-    test('should get a part of the log', async () => {
-      const command = ['vaults', 'log', '-np', dataDir, '-d', '2', vaultName];
-
-      const result = await testUtils.pkStdio([...command], {
-        env: {},
-        cwd: dataDir,
-      });
-      expect(result.exitCode).toEqual(0);
-      expect(result.stdout).not.toContain(writeF1Oid);
-      expect(result.stdout).toContain(writeF2Oid);
-      expect(result.stdout).toContain(writeF3Oid);
-    });
-    test('should get a specific writeF', async () => {
-      const command = [
-        'vaults',
-        'log',
-        '-np',
-        dataDir,
-        '-d',
-        '1',
-        vaultName,
-        '-ci',
-        writeF2Oid,
-      ];
-
-      const result = await testUtils.pkStdio([...command], {
-        env: {},
-        cwd: dataDir,
-      });
-      expect(result.exitCode).toEqual(0);
-      expect(result.stdout).not.toContain(writeF1Oid);
-      expect(result.stdout).toContain(writeF2Oid);
-      expect(result.stdout).not.toContain(writeF3Oid);
-    });
-    test.todo('test formatting of the output');
-  });
-  // Fixme: temperamental problem with formatting the output. Fails sometimes due to an added space
-  describe('commandScanNode', () => {
-    test(
-      'should return the vaults names and ids of the remote vault',
-      async () => {
-        let remoteOnline: PolykeyAgent | undefined;
-        try {
-          remoteOnline = await PolykeyAgent.createPolykeyAgent({
-            password,
-            options: {
-              nodePath: path.join(dataDir, 'remoteOnline'),
-              agentServiceHost: '127.0.0.1',
-              clientServiceHost: '127.0.0.1',
-              keys: {
-                passwordOpsLimit: keysUtils.passwordOpsLimits.min,
-                passwordMemLimit: keysUtils.passwordMemLimits.min,
-                strictMemoryLock: false,
-              },
-            },
-            logger,
-          });
-          const remoteOnlineNodeId = remoteOnline.keyRing.getNodeId();
-          const remoteOnlineNodeIdEncoded =
-            nodesUtils.encodeNodeId(remoteOnlineNodeId);
-          await polykeyAgent.nodeManager.setNode(
-            remoteOnlineNodeId,
-            [remoteOnline.agentServiceHost, remoteOnline.agentServicePort],
-            {
-              mode: 'direct',
-              connectedTime: Date.now(),
-              scopes: ['global'],
-            },
-          );
-
-          await remoteOnline.gestaltGraph.setNode({
-            nodeId: polykeyAgent.keyRing.getNodeId(),
-          });
-
-          const commands1 = [
-            'vaults',
-            'scan',
-            remoteOnlineNodeIdEncoded,
-            '-np',
-            dataDir,
-          ];
-          const result1 = await testUtils.pkStdio(commands1, {
-            env: { PK_PASSWORD: 'password' },
-            cwd: dataDir,
-          });
-          expect(result1.exitCode).toEqual(sysexits.NOPERM);
-          expect(result1.stderr).toContain(
-            'ErrorVaultsPermissionDenied: Permission was denied - Scanning is not allowed for',
-          );
-
-          await remoteOnline.gestaltGraph.setGestaltAction(
-            ['node', polykeyAgent.keyRing.getNodeId()],
-            'notify',
-          );
-
-          const commands2 = [
-            'vaults',
-            'scan',
-            remoteOnlineNodeIdEncoded,
-            '-np',
-            dataDir,
-          ];
-          const result2 = await testUtils.pkStdio(commands2, {
-            env: { PK_PASSWORD: 'password' },
-            cwd: dataDir,
-          });
-          expect(result2.exitCode).toEqual(sysexits.NOPERM);
-          expect(result2.stderr).toContain(
-            'ErrorVaultsPermissionDenied: Permission was denied - Scanning is not allowed for',
-          );
-
-          await remoteOnline.gestaltGraph.setGestaltAction(
-            ['node', polykeyAgent.keyRing.getNodeId()],
-            'scan',
-          );
-
-          const vault1Id = await remoteOnline.vaultManager.createVault(
-            'Vault1' as VaultName,
-          );
-          const vault2Id = await remoteOnline.vaultManager.createVault(
-            'Vault2' as VaultName,
-          );
-          const vault3Id = await remoteOnline.vaultManager.createVault(
-            'Vault3' as VaultName,
-          );
-          const nodeId = polykeyAgent.keyRing.getNodeId();
-          await remoteOnline.acl.setVaultAction(vault1Id, nodeId, 'clone');
-          await remoteOnline.acl.setVaultAction(vault2Id, nodeId, 'pull');
-          await remoteOnline.acl.setVaultAction(vault2Id, nodeId, 'clone');
-          const commands3 = [
-            'vaults',
-            'scan',
-            remoteOnlineNodeIdEncoded,
-            '-np',
-            dataDir,
-          ];
-          const result3 = await testUtils.pkStdio(commands3, {
-            env: { PK_PASSWORD: 'password' },
-            cwd: dataDir,
-          });
-          expect(result3.exitCode).toBe(0);
-          expect(result3.stdout).toMatch(/Vault1\t.*\tclone/);
-          expect(JSON.stringify(result3.stdout)).toContain(
-            JSON.stringify(
-              `Vault1\t${vaultsUtils.encodeVaultId(
-                vault1Id,
-              )}\tclone\nVault2\t${vaultsUtils.encodeVaultId(
-                vault2Id,
-              )}\tpull,clone\n`,
-            ),
-          );
-          expect(result3.stdout).not.toContain(
-            `Vault3\t${vaultsUtils.encodeVaultId(vault3Id)}`,
-          );
-        } finally {
-          await remoteOnline?.stop();
-        }
-      },
-      globalThis.defaultTimeout * 2,
-    );
-  });
-});
diff --git a/tests/vaults/version.test.ts b/tests/vaults/version.test.ts
new file mode 100644
index 00000000..73b77da0
--- /dev/null
+++ b/tests/vaults/version.test.ts
@@ -0,0 +1,198 @@
+import type { VaultName } from 'polykey/dist/vaults/types';
+import type { GestaltNodeInfo } from 'polykey/dist/gestalts/types';
+import path from 'path';
+import fs from 'fs';
+import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
+import PolykeyAgent from 'polykey/dist/PolykeyAgent';
+import * as ids from 'polykey/dist/ids';
+import sysexits from 'polykey/dist/utils/sysexits';
+import * as keysUtils from 'polykey/dist/keys/utils';
+import * as testUtils from '../utils';
+
+describe('commandVaultVersion', () => {
+  const password = 'password';
+  const logger = new Logger('CLI Test', LogLevel.WARN, [new StreamHandler()]);
+  let dataDir: string;
+  let passwordFile: string;
+  let polykeyAgent: PolykeyAgent;
+  let vaultNumber: number;
+  let vaultName: VaultName;
+  const nodeIdGenerator = ids.createNodeIdGenerator();
+  const nodeId1 = nodeIdGenerator();
+  const nodeId2 = nodeIdGenerator();
+  const nodeId3 = nodeIdGenerator();
+  const node1: GestaltNodeInfo = {
+    nodeId: nodeId1,
+  };
+  const node2: GestaltNodeInfo = {
+    nodeId: nodeId2,
+  };
+  const node3: GestaltNodeInfo = {
+    nodeId: nodeId3,
+  };
+  // Helper functions
+  function genVaultName() {
+    vaultNumber++;
+    return `vault-${vaultNumber}` as VaultName;
+  }
+  beforeEach(async () => {
+    dataDir = await fs.promises.mkdtemp(
+      path.join(globalThis.tmpDir, 'polykey-test-'),
+    );
+    passwordFile = path.join(dataDir, 'passwordFile');
+    await fs.promises.writeFile(passwordFile, 'password');
+    polykeyAgent = await PolykeyAgent.createPolykeyAgent({
+      password,
+      options: {
+        nodePath: dataDir,
+        agentServiceHost: '127.0.0.1',
+        clientServiceHost: '127.0.0.1',
+        keys: {
+          passwordOpsLimit: keysUtils.passwordOpsLimits.min,
+          passwordMemLimit: keysUtils.passwordMemLimits.min,
+          strictMemoryLock: false,
+        },
+      },
+      logger: logger,
+    });
+    await polykeyAgent.gestaltGraph.setNode(node1);
+    await polykeyAgent.gestaltGraph.setNode(node2);
+    await polykeyAgent.gestaltGraph.setNode(node3);
+
+    vaultNumber = 0;
+
+    // Authorize session
+    await testUtils.pkStdio(
+      ['agent', 'unlock', '-np', dataDir, '--password-file', passwordFile],
+      {
+        env: {},
+        cwd: dataDir,
+      },
+    );
+    vaultName = genVaultName();
+  });
+  afterEach(async () => {
+    await polykeyAgent.stop();
+    await fs.promises.rm(dataDir, {
+      force: true,
+      recursive: true,
+    });
+  });
+
+  test('should switch the version of a vault', async () => {
+    const vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
+    const id = polykeyAgent.vaultManager.getVaultId(vaultName);
+    expect(id).toBeTruthy();
+
+    const secret1 = { name: 'Secret-1', content: 'Secret-1-content' };
+    const secret2 = { name: 'Secret-1', content: 'Secret-2-content' };
+
+    const ver1Oid = await polykeyAgent.vaultManager.withVaults(
+      [vaultId],
+      async (vault) => {
+        await vault.writeF(async (efs) => {
+          await efs.writeFile(secret1.name, secret1.content);
+        });
+        const ver1Oid = (await vault.log(undefined, 1))[0].commitId;
+
+        await vault.writeF(async (efs) => {
+          await efs.writeFile(secret2.name, secret2.content);
+        });
+        return ver1Oid;
+      },
+    );
+
+    const command = ['vaults', 'version', '-np', dataDir, vaultName, ver1Oid];
+
+    const result = await testUtils.pkStdio([...command], {
+      env: {},
+      cwd: dataDir,
+    });
+    expect(result.exitCode).toBe(0);
+
+    await polykeyAgent.vaultManager.withVaults([vaultId], async (vault) => {
+      const fileContents = await vault.readF(async (efs) => {
+        return (await efs.readFile(secret1.name)).toString();
+      });
+      expect(fileContents).toStrictEqual(secret1.content);
+    });
+  });
+  test('should switch the version of a vault to the latest version', async () => {
+    const vaultId = await polykeyAgent.vaultManager.createVault(vaultName);
+    const id = polykeyAgent.vaultManager.getVaultId(vaultName);
+    expect(id).toBeTruthy();
+
+    const secret1 = { name: 'Secret-1', content: 'Secret-1-content' };
+    const secret2 = { name: 'Secret-1', content: 'Secret-2-content' };
+
+    const ver1Oid = await polykeyAgent.vaultManager.withVaults(
+      [vaultId],
+      async (vault) => {
+        await vault.writeF(async (efs) => {
+          await efs.writeFile(secret1.name, secret1.content);
+        });
+        const ver1Oid = (await vault.log(undefined, 1))[0].commitId;
+
+        await vault.writeF(async (efs) => {
+          await efs.writeFile(secret2.name, secret2.content);
+        });
+        return ver1Oid;
+      },
+    );
+
+    const command = ['vaults', 'version', '-np', dataDir, vaultName, ver1Oid];
+
+    const result = await testUtils.pkStdio([...command], {
+      env: {},
+      cwd: dataDir,
+    });
+    expect(result.exitCode).toBe(0);
+
+    const command2 = ['vaults', 'version', '-np', dataDir, vaultName, 'last'];
+
+    const result2 = await testUtils.pkStdio([...command2], {
+      env: {},
+      cwd: dataDir,
+    });
+    expect(result2.exitCode).toBe(0);
+  });
+  test('should handle invalid version IDs', async () => {
+    await polykeyAgent.vaultManager.createVault(vaultName);
+    const id = polykeyAgent.vaultManager.getVaultId(vaultName);
+    expect(id).toBeTruthy();
+
+    const command = [
+      'vaults',
+      'version',
+      '-np',
+      dataDir,
+      vaultName,
+      'NOT_A_VALID_CHECKOUT_ID',
+    ];
+
+    const result = await testUtils.pkStdio([...command], {
+      env: {},
+      cwd: dataDir,
+    });
+    expect(result.exitCode).toBe(sysexits.USAGE);
+
+    expect(result.stderr).toContain('ErrorVaultReferenceInvalid');
+  });
+  test('should throw an error if the vault is not found', async () => {
+    const command = [
+      'vaults',
+      'version',
+      '-np',
+      dataDir,
+      'zLnM7puKobbh4YXEz66StAq',
+      'NOT_A_VALID_CHECKOUT_ID',
+    ];
+
+    const result = await testUtils.pkStdio([...command], {
+      env: {},
+      cwd: dataDir,
+    });
+    expect(result.exitCode).toBe(sysexits.USAGE);
+    expect(result.stderr).toContain('ErrorVaultsVaultUndefined');
+  });
+});
