diff --git a/deadlock-plugins/deadlock-extension/src/core/api.service.ts b/deadlock-plugins/deadlock-extension/src/core/api.service.ts
index 9d0295643b94a877060bac29b3c4a3ef98896d5d..b362180001e3dcb17848c3649ad430d0fc380c69 100644
--- a/deadlock-plugins/deadlock-extension/src/core/api.service.ts
+++ b/deadlock-plugins/deadlock-extension/src/core/api.service.ts
@@ -14,7 +14,7 @@ export default class ApiService {
   private axiosInstance: AxiosInstance;
   private static _instance: ApiService;
 
-  static getInstance(): ApiService {
+  static get instance(): ApiService {
     if (!ApiService._instance) {
       ApiService._instance = new ApiService();
     }
@@ -33,18 +33,6 @@ export default class ApiService {
     this.initApiInterceptor();
   }
 
-  private get controller(): Controller {
-    return Controller.getInstance();
-  }
-
-  private get extensionStore(): ExtensionStore {
-    return ExtensionStore.getInstance();
-  }
-
-  private get keycloackConnection(): KeycloakOAuth2DeviceFlowConnection {
-    return KeycloakOAuth2DeviceFlowConnection.getInstance();
-  }
-
   initApiInterceptor() {
     this.initRequestInterceptor();
     this.initResponseInterceptor();
@@ -53,7 +41,7 @@ export default class ApiService {
   private initRequestInterceptor() {
     this.axiosInstance.interceptors.request.use(
       async (config) => {
-        const accessToken = await this.extensionStore.getAccessToken();
+        const accessToken = await ExtensionStore.instance.getAccessToken();
         if (accessToken && config.headers) {
           config.headers['authorization'] = `BEARER ${accessToken}`;
         }
@@ -98,14 +86,14 @@ export default class ApiService {
 
   private async onRetry(originalConfig) {
     try {
-      const storedRefreshToken = await this.extensionStore.getRefreshToken();
-      const { accessToken, refreshToken } = await this.keycloackConnection.getToken({
+      const storedRefreshToken = await ExtensionStore.instance.getRefreshToken();
+      const { accessToken, refreshToken } = await KeycloakOAuth2DeviceFlowConnection.instance.getToken({
         refreshToken: storedRefreshToken,
         openLink: Controller.openBrowserWithUrl,
       });
 
-      await this.extensionStore.setAccessToken(accessToken);
-      await this.extensionStore.setRefreshToken(refreshToken);
+      await ExtensionStore.instance.setAccessToken(accessToken);
+      await ExtensionStore.instance.setRefreshToken(refreshToken);
 
       this.axiosInstance.defaults.headers.common['authorization'] = `BEARER ${accessToken}`;
       return this.axiosInstance(originalConfig);
@@ -125,7 +113,7 @@ export default class ApiService {
 
   private async onInvalidRefreshToken(originalConfig) {
     try {
-      await this.controller.authenticate();
+      await Controller.instance.authenticate();
       return this.axiosInstance(originalConfig);
     } catch (_error) {
       return Promise.reject(_error);
@@ -161,7 +149,7 @@ export default class ApiService {
   async pingUpdateWorkTime(): Promise<MissionUser> {
     return this.axiosInstance
       .post<MissionUser>(
-        `users/${(await this.getCurrentUser()).id}/missions/${UserMission.getInstance().missionId}/worktime`,
+        `users/${(await this.getCurrentUser()).id}/missions/${UserMission.instance.missionId}/worktime`,
         {
           action: 'PING',
         },
@@ -171,7 +159,7 @@ export default class ApiService {
 
   async startUpdateWorkTime() {
     return this.axiosInstance
-      .post(`users/${(await this.getCurrentUser()).id}/missions/${UserMission.getInstance().missionId}/worktime`, {
+      .post(`users/${(await this.getCurrentUser()).id}/missions/${UserMission.instance.missionId}/worktime`, {
         action: 'START',
       })
       .then((res) => res.data);
@@ -180,7 +168,7 @@ export default class ApiService {
   async submitAttempt(attempt: Attempt): Promise<MissionUser> {
     return this.axiosInstance
       .post<MissionUser>(
-        `/users/${(await this.getCurrentUser()).id}/missions/${UserMission.getInstance().missionId}/solve/desktop`,
+        `/users/${(await this.getCurrentUser()).id}/missions/${UserMission.instance.missionId}/solve/desktop`,
         attempt,
       )
       .then((res) => res.data);
diff --git a/deadlock-plugins/deadlock-extension/src/core/commandHandler.ts b/deadlock-plugins/deadlock-extension/src/core/commandHandler.ts
index 6dde3a57fc7f225dabfdafd7b9cc27ad107ce2c9..b73494fb57264fefeb9b8d2a4e2e0a2f43d975b1 100644
--- a/deadlock-plugins/deadlock-extension/src/core/commandHandler.ts
+++ b/deadlock-plugins/deadlock-extension/src/core/commandHandler.ts
@@ -1,16 +1,27 @@
 import { Command, commands } from 'vscode';
 import Controller from './controller';
+
 export class CommandHandler {
-  constructor(private controller: Controller) {
-    this.initCommandHandler();
+  private static _instance?: CommandHandler;
+  public readonly disconnectCommand: Command;
+  public readonly authenticateCommand: Command = { title: 'Authenticate', command: 'deadlock.authenticate' };
+  public readonly openUrlInBrowserCommand: Command = { title: 'Open url in browser', command: 'vscode.open' };
+
+  public static get instance(): CommandHandler {
+    if (!this._instance) {
+      this._instance = new CommandHandler();
+    }
+    return this._instance;
   }
 
-  initCommandHandler() {
-    commands.registerCommand(disconnectCommand.command, this.controller.disconnect.bind(this.controller));
-    commands.registerCommand(authenticateCommand.command, this.controller.authenticate.bind(this.controller));
+  private constructor() {
+    this.disconnectCommand = { title: 'Disconnect', command: 'deadlock.disconnect' };
+    this.authenticateCommand = { title: 'Authenticate', command: 'deadlock.authenticate' };
+    this.openUrlInBrowserCommand = { title: 'Open url in browser', command: 'vscode.open' };
+    commands.registerCommand(this.disconnectCommand.command, Controller.instance.disconnect.bind(Controller.instance));
+    commands.registerCommand(
+      this.authenticateCommand.command,
+      Controller.instance.authenticate.bind(Controller.instance),
+    );
   }
 }
-
-export const disconnectCommand: Command = { title: 'Disconnect', command: 'deadlock.disconnect' };
-export const authenticateCommand: Command = { title: 'Authenticate', command: 'deadlock.authenticate' };
-export const openUrlInBrowserCommand: Command = { title: 'Open url in browser', command: 'vscode.open' };
diff --git a/deadlock-plugins/deadlock-extension/src/core/controller.ts b/deadlock-plugins/deadlock-extension/src/core/controller.ts
index 02fca9269d04aec578abad1704fbe1f3478f1a4a..5541b40178643dcac5f90fafa2120fd38a281845 100644
--- a/deadlock-plugins/deadlock-extension/src/core/controller.ts
+++ b/deadlock-plugins/deadlock-extension/src/core/controller.ts
@@ -1,6 +1,6 @@
 import BriefingView from '../view/briefingView';
 import QuickSetupView from '../view/quickSetupView';
-import { CommandHandler, openUrlInBrowserCommand } from './commandHandler';
+import { CommandHandler } from './commandHandler';
 import ExtensionStore from './extensionStore';
 import KeycloakOAuth2DeviceFlowConnection from './keycloakOAuth2DeviceFlowConnection';
 import { MissionDevContainer } from './mission/missionDevContainer';
@@ -20,43 +20,25 @@ import Mission from '../model/mission';
 import ApiService from './api.service';
 
 export default class Controller {
-  private static instance: Controller;
-  private commandHandler: CommandHandler;
+  private static _instance: Controller;
   private briefingView?: BriefingView;
   private quickSetupView: QuickSetupView;
-  private _extensionStore: ExtensionStore;
 
-  public get extensionStore() {
-    return this._extensionStore;
-  }
-
-  private get connection(): KeycloakOAuth2DeviceFlowConnection {
-    return KeycloakOAuth2DeviceFlowConnection.getInstance();
-  }
-
-  private get apiService(): ApiService {
-    return ApiService.getInstance();
-  }
-
-  private constructor(public readonly context: ExtensionContext) {
-    this._extensionStore = ExtensionStore.getInstance(context);
+  public constructor(public readonly context: ExtensionContext) {
+    if (Controller._instance) {
+      throw new Error('Controller is a singleton');
+    }
+    Controller._instance = this;
     if (isDocker()) {
       this.briefingView = new BriefingView();
     }
-    this.quickSetupView = new QuickSetupView(context.extensionUri);
-    this.commandHandler = new CommandHandler(this);
+    this.quickSetupView = new QuickSetupView();
 
     this.init();
   }
 
-  public static getInstance(context?: ExtensionContext): Controller {
-    if (!Controller.instance) {
-      if (context === undefined) {
-        throw new Error('Controller needs a context when instantiated');
-      }
-      Controller.instance = new Controller(context);
-    }
-    return Controller.instance;
+  public static get instance(): Controller {
+    return Controller._instance;
   }
 
   getChallenge(missionId: string): Mission | undefined {
@@ -67,7 +49,7 @@ export default class Controller {
 
   public async getSolution(missionId: string, reviewedId: string) {
     try {
-      const solution = await this.apiService.getSolution(missionId);
+      const solution = await ApiService.instance.getSolution(missionId);
       const solutionFolder = join(getReviewedStudentWorkdirPath(reviewedId), missionId, '.solution');
       const tarName = 'solution.tar.gz';
       const tarPath = join(solutionFolder, tarName);
@@ -122,7 +104,7 @@ export default class Controller {
       },
     });
 
-    this.quickSetupView.isAlreadyConnected = (await this._extensionStore.getAccessToken()) !== undefined;
+    this.quickSetupView.isAlreadyConnected = (await ExtensionStore.instance.getAccessToken()) !== undefined;
   }
 
   public async disconnect() {
@@ -139,7 +121,7 @@ export default class Controller {
       extensionWarn(e);
     }
     try {
-      await this.extensionStore.clear();
+      await ExtensionStore.instance.clear();
     } catch (e) {
       extensionWarn('Could not clear extension store');
       extensionWarn(e);
@@ -148,21 +130,23 @@ export default class Controller {
   }
 
   public async createSshKeyPair() {
-    const { publicKey, privateKey } = await this.apiService.getUserSshKey();
+    const { publicKey, privateKey } = await ApiService.instance.getUserSshKey();
     await createSshKeyFiles(publicKey, privateKey);
   }
 
   public async authenticate() {
-    await this.connection.registerDevice();
-    const tokens = await this.connection.getToken({ openLink: Controller.openBrowserWithUrl });
-    await this._extensionStore.setAccessToken(tokens.accessToken);
-    await this._extensionStore.setRefreshToken(tokens.refreshToken);
+    await KeycloakOAuth2DeviceFlowConnection.instance.registerDevice();
+    const tokens = await KeycloakOAuth2DeviceFlowConnection.instance.getToken({
+      openLink: Controller.openBrowserWithUrl,
+    });
+    await ExtensionStore.instance.setAccessToken(tokens.accessToken);
+    await ExtensionStore.instance.setRefreshToken(tokens.refreshToken);
     await this.createSshKeyPair();
     this.quickSetupView.isAlreadyConnected = true;
   }
 
   public static openBrowserWithUrl(url: string) {
-    commands.executeCommand(openUrlInBrowserCommand.command, Uri.parse(url));
+    commands.executeCommand(CommandHandler.instance.openUrlInBrowserCommand.command, Uri.parse(url));
   }
 
   public async launchMission({
@@ -178,18 +162,18 @@ export default class Controller {
   }) {
     window.showInformationMessage(`vous lancez la mission ${missionId}`);
 
-    const hadBeenConnected = (await this._extensionStore.getAccessToken()) !== undefined;
+    const hadBeenConnected = (await ExtensionStore.instance.getAccessToken()) !== undefined;
 
     if (!hadBeenConnected) {
       await this.authenticate();
       window.showInformationMessage('Connexion validée');
     }
 
-    const reviewer = await this.apiService.getCurrentUser();
+    const reviewer = await ApiService.instance.getCurrentUser();
 
     if (!!revieweeId && revieweeId !== reviewer.id) {
       try {
-        await this.apiService.grantAccessToRepository(revieweeId, missionId);
+        await ApiService.instance.grantAccessToRepository(revieweeId, missionId);
       } catch (e) {
         if (hasStatusNumber(e)) {
           if (e.status === 403) {
@@ -204,7 +188,7 @@ export default class Controller {
         }
       }
       try {
-        await Controller.getInstance().getSolution(missionId, revieweeId);
+        await this.getSolution(missionId, revieweeId);
       } catch (e) {
         window.showErrorMessage(`Une erreur est survenue lors de la récupération de la solution`);
         extensionError(e);
diff --git a/deadlock-plugins/deadlock-extension/src/core/extensionStore.ts b/deadlock-plugins/deadlock-extension/src/core/extensionStore.ts
index 2ccb8749dca4c345316711cd1371ee84113cef88..ff52c9b672f7dd3c7a32462fabd53480c1ff21a4 100644
--- a/deadlock-plugins/deadlock-extension/src/core/extensionStore.ts
+++ b/deadlock-plugins/deadlock-extension/src/core/extensionStore.ts
@@ -1,12 +1,13 @@
-import { ExtensionContext, SecretStorage } from 'vscode';
+import { SecretStorage } from 'vscode';
 import { extensionLog as log } from '../recorder/utils/log';
+import Controller from './controller';
 
 export default class ExtensionStore {
-  private static instance: ExtensionStore;
+  private static _instance: ExtensionStore;
   private secretStorage: SecretStorage;
 
-  private constructor(context: ExtensionContext) {
-    this.secretStorage = context.secrets;
+  private constructor() {
+    this.secretStorage = Controller.instance.context.secrets;
   }
 
   public async clear() {
@@ -16,13 +17,12 @@ export default class ExtensionStore {
       this.secretStorage.delete(SecretStoreKey.RefreshTokenKey);
   }
 
-  public static getInstance(context?: ExtensionContext): ExtensionStore {
-    if (!ExtensionStore.instance) {
-      if (!context) throw new Error('ExtensionStore should be initiate with a storage first time');
-      ExtensionStore.instance = new ExtensionStore(context);
+  public static get instance(): ExtensionStore {
+    if (!ExtensionStore._instance) {
+      ExtensionStore._instance = new ExtensionStore();
     }
 
-    return ExtensionStore.instance;
+    return ExtensionStore._instance;
   }
 
   public getAccessToken(): Thenable<string | undefined> {
diff --git a/deadlock-plugins/deadlock-extension/src/core/gitMission.ts b/deadlock-plugins/deadlock-extension/src/core/gitMission.ts
index 794137e58b1e4dd0571f0632178edb778dd97ac4..dc0db9aa7124c4c5b0b296707da1894dd6068fe6 100644
--- a/deadlock-plugins/deadlock-extension/src/core/gitMission.ts
+++ b/deadlock-plugins/deadlock-extension/src/core/gitMission.ts
@@ -13,10 +13,18 @@ const defaultRemote = 'origin';
 type Branch = 'master' | 'live';
 
 export default class GitMission {
+  private static _instance: GitMission;
+  public static get instance(): GitMission {
+    if (!GitMission._instance) {
+      GitMission._instance = new GitMission();
+    }
+    return GitMission._instance;
+  }
+
   private prefix = 'DEADLOCK-RECORDER';
   private git: SimpleGit;
 
-  constructor() {
+  private constructor() {
     const options: Partial<SimpleGitOptions> = {
       baseDir: GITEA_PATH_IC,
       binary: 'git',
@@ -36,7 +44,7 @@ export default class GitMission {
 
   async setupSshAgent() {
     try {
-      const gitea = await ApiService.getInstance().getGiteaPublicProperties();
+      const gitea = await ApiService.instance.getGiteaPublicProperties();
       await exec(`ssh-add /tmp/.ssh/id_rsa`);
       await exec(`eval "$(ssh-agent -s)" && ssh-keyscan -p ${gitea.sshPort} -H ${gitea.sshHost} >> ~/.ssh/known_hosts`);
     } catch (err) {
@@ -58,7 +66,7 @@ export default class GitMission {
   }
 
   async getAuthor(): Promise<string> {
-    return (await UserMission.getInstance().getGiteaUser()).username;
+    return (await UserMission.instance.getGiteaUser()).username;
   }
 
   async init() {
@@ -73,10 +81,10 @@ export default class GitMission {
         return Promise.resolve(this);
       }
 
-      const giteaUser = await UserMission.getInstance().getGiteaUser();
+      const giteaUser = await UserMission.instance.getGiteaUser();
 
       await this.git.addRemote(defaultRemote, await this.getRemotePath());
-      await this.git.addConfig('user.email', await UserMission.getInstance().getEmail(), false, 'local');
+      await this.git.addConfig('user.email', await UserMission.instance.getEmail(), false, 'local');
       await this.git.addConfig(
         'user.name',
         `${giteaUser.details.lastName} ${giteaUser.details.firstName}`,
@@ -93,10 +101,10 @@ export default class GitMission {
   }
 
   private async getRemotePath() {
-    const giteaConfig = await ApiService.getInstance().getGiteaPublicProperties();
+    const giteaConfig = await ApiService.instance.getGiteaPublicProperties();
     return `ssh://git@${giteaConfig.sshHost}:${giteaConfig.sshPort}/${
-      (await UserMission.getInstance().getGiteaUser()).username
-    }/${UserMission.getInstance().missionId}`;
+      (await UserMission.instance.getGiteaUser()).username
+    }/${UserMission.instance.missionId}`;
   }
 
   async readRemote() {
diff --git a/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.ts b/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.ts
index 587f973416f5976fa3af5c2e99b1ba62b31791d3..39ba2e4c019b66b4b701bdbc7415603ec132f67f 100644
--- a/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.ts
+++ b/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.ts
@@ -35,7 +35,7 @@ export default class KeycloakOAuth2DeviceFlowConnection {
     this.deviceAuthorizationRequestResponse = {};
   }
 
-  public static getInstance(): KeycloakOAuth2DeviceFlowConnection {
+  public static get instance(): KeycloakOAuth2DeviceFlowConnection {
     if (!KeycloakOAuth2DeviceFlowConnection._instance) {
       KeycloakOAuth2DeviceFlowConnection._instance = new KeycloakOAuth2DeviceFlowConnection();
     }
diff --git a/deadlock-plugins/deadlock-extension/src/core/mission/model/userMission.ts b/deadlock-plugins/deadlock-extension/src/core/mission/model/userMission.ts
index 359af9cb47dd5242244a0a8567d96af6d6609793..829a829430e584589db3d4d4df4b1eacd08e93b4 100644
--- a/deadlock-plugins/deadlock-extension/src/core/mission/model/userMission.ts
+++ b/deadlock-plugins/deadlock-extension/src/core/mission/model/userMission.ts
@@ -24,19 +24,15 @@ export default class UserMission implements UserMissionModel {
     UserMission._instance = this;
   }
 
-  public static getInstance(): UserMission {
+  public static get instance(): UserMission {
     if (!UserMission._instance) {
       return (this._instance = new UserMission(JSON.parse(readFileSync(USER_MISSION_PATH, 'utf8'))));
     }
     return UserMission._instance;
   }
 
-  private get apiService(): ApiService {
-    return ApiService.getInstance();
-  }
-
   public async getGiteaUser(): Promise<User & { username: string }> {
-    const giteaUser: User & { username?: string } = this.reviewee ?? (await this.apiService.getCurrentUser());
+    const giteaUser: User & { username?: string } = this.reviewee ?? (await ApiService.instance.getCurrentUser());
     return { ...giteaUser, username: giteaUser.id.split('-').join('') };
   }
 
@@ -69,7 +65,7 @@ export default class UserMission implements UserMissionModel {
           missionId,
           storyId,
           missionVersion,
-          reviewee: revieweeId ? await ApiService.getInstance().getUser(revieweeId) : undefined,
+          reviewee: revieweeId ? await ApiService.instance.getUser(revieweeId) : undefined,
         } as UserMissionModel,
         null,
         2,
diff --git a/deadlock-plugins/deadlock-extension/src/extension.ts b/deadlock-plugins/deadlock-extension/src/extension.ts
index ba3d660ebf7525b69a16978c6606fd0e356b26ba..093a4d10fb36a6db2c6dce4c140f0e8ff2089300 100644
--- a/deadlock-plugins/deadlock-extension/src/extension.ts
+++ b/deadlock-plugins/deadlock-extension/src/extension.ts
@@ -1,21 +1,21 @@
 import { window, ExtensionContext, workspace, commands } from 'vscode';
-import Controller from './core/controller';
 import isDocker from './core/utils/isdocker';
 import Recorder from './recorder/recorder';
 import { extensionError as error } from './recorder/utils/log';
 import { DepNodeProvider } from './view/deadlockPanel';
 import { CommandTreeProvider } from './view/CommandTree';
 import StartedMissionsView from './view/startedMissionsView';
+import Controller from './core/controller';
 
 export async function activate(context: ExtensionContext) {
+  new Controller(context);
   window.showInformationMessage('Bienvenue sur Deadlock!');
-  Controller.getInstance(context);
 
   const workspaceFolders = workspace.workspaceFolders?.toString() ?? '';
   if (!workspaceFolders) window.showInformationMessage('Pas de répertoires ouverts');
   const deadlockPanelProvider = new DepNodeProvider();
   window.registerTreeDataProvider('deadlockPanel', deadlockPanelProvider);
-  window.registerWebviewViewProvider('startedMissions', new StartedMissionsView(context));
+  window.registerWebviewViewProvider('startedMissions', new StartedMissionsView());
 
   if (isDocker()) {
     commands.executeCommand('setContext', 'deadlock.inContainer', true);
diff --git a/deadlock-plugins/deadlock-extension/src/recorder/recorder.ts b/deadlock-plugins/deadlock-extension/src/recorder/recorder.ts
index 0eaa8e4716a2acc57e019fbc095f4a0956ab7a5e..20b1cd8b1b9fbf7ff8987b117bfac00b198fc9e0 100644
--- a/deadlock-plugins/deadlock-extension/src/recorder/recorder.ts
+++ b/deadlock-plugins/deadlock-extension/src/recorder/recorder.ts
@@ -8,13 +8,13 @@ import aquirePermissions from './utils/permission';
 import UserMission from '../core/mission/model/userMission';
 import ApiService from '../core/api.service';
 import { window } from 'vscode';
+import { pushOnCommitQueueIfNotReviewing } from './utils/gitea';
 
 export default class Recorder {
-  private _gitMission?: GitMission;
   private static _instance?: Recorder;
 
   private get userMission(): UserMission {
-    return UserMission.getInstance();
+    return UserMission.instance;
   }
 
   private constructor() {
@@ -28,22 +28,14 @@ export default class Recorder {
     return this._instance;
   }
 
-  public get gitMission(): GitMission {
-    return this._gitMission!;
-  }
-
   async setupProject(gitMission: GitMission) {
     const argsArray: string[] = [`user-git-${(await this.userMission.getGiteaUser()).username}`];
 
-    if(!this.userMission.isReviewing()) {
+    if (!this.userMission.isReviewing()) {
       argsArray.push('.git');
     }
 
-    await copyProjectSources(
-      GITEA_PATH_IC,
-      MISSION_PATH_IC,
-      ...argsArray
-    );
+    await copyProjectSources(GITEA_PATH_IC, MISSION_PATH_IC, ...argsArray);
 
     if (!this.userMission.isReviewing()) {
       renameTempToUserGitFiles(MISSION_PATH_IC, await gitMission.getAuthor());
@@ -67,13 +59,16 @@ export default class Recorder {
   async run() {
     try {
       await aquirePermissions();
-      // TODO refactor make it as a sigleton
-      this._gitMission = await new GitMission().init();
-      await this.setupFromRemoteRepo(this._gitMission);
-      await this.setupProject(this._gitMission);
+      await GitMission.instance.init();
+      const isStarted = await GitMission.instance.isRemoteRepoExist();
+      await this.setupFromRemoteRepo(GitMission.instance);
+      await this.setupProject(GitMission.instance);
+      if (!isStarted) {
+        pushOnCommitQueueIfNotReviewing(GitMission.instance, 'Auto');
+      }
       if (!this.userMission.isReviewing()) {
         if (ENABLE_AUTOMATIC_SAVE) {
-          new AutomaticSave(MISSION_PATH_IC, this._gitMission);
+          new AutomaticSave(MISSION_PATH_IC, GitMission.instance);
         }
         try {
           runTimer();
@@ -82,7 +77,7 @@ export default class Recorder {
           error(e);
         }
       } else {
-        await this.gitMission.forgetSshKeys();
+        await GitMission.instance.forgetSshKeys();
       }
     } catch (e) {
       error('Cannot setup user repo.');
@@ -92,7 +87,7 @@ export default class Recorder {
 }
 
 export async function runTimer() {
-  const apiService = ApiService.getInstance();
+  const apiService = ApiService.instance;
   try {
     await apiService.startUpdateWorkTime();
     setInterval(async () => {
diff --git a/deadlock-plugins/deadlock-extension/src/recorder/utils/gitea.ts b/deadlock-plugins/deadlock-extension/src/recorder/utils/gitea.ts
index f307b2b591568691fb4c51a1616f8ff9ae3ea1ef..d3aaa558cfd410a4a87e8ff132c1c38b590b3cf6 100644
--- a/deadlock-plugins/deadlock-extension/src/recorder/utils/gitea.ts
+++ b/deadlock-plugins/deadlock-extension/src/recorder/utils/gitea.ts
@@ -40,7 +40,7 @@ export async function pushOnCommitQueueIfNotReviewing(
   from: 'Run' | 'Auto' | 'HttpServer',
   callback?: (commitResult: CommitResult) => void,
 ) {
-  if (!UserMission.getInstance().isReviewing()) {
+  if (!UserMission.instance.isReviewing()) {
     await pushOnCommitQueue(gitMission, from, callback);
   }
 }
diff --git a/deadlock-plugins/deadlock-extension/src/recorder/utils/workdir.ts b/deadlock-plugins/deadlock-extension/src/recorder/utils/workdir.ts
index acb35be4f28d154d6ed6db0078c3f4271c70ad80..5bac1dfbe438f148dea7907a3a70c5417f7607fa 100644
--- a/deadlock-plugins/deadlock-extension/src/recorder/utils/workdir.ts
+++ b/deadlock-plugins/deadlock-extension/src/recorder/utils/workdir.ts
@@ -4,6 +4,7 @@ import { join } from 'path';
 import { log } from './log';
 import { promisify } from 'util';
 import { mkdir, rm } from 'fs/promises';
+import Controller from '../../core/controller';
 
 const exec = promisify(execCallback);
 const PREFIX = '[DEADLOCK-RECORDER]';
@@ -88,3 +89,7 @@ export async function emptyDirectories(...directoryPaths: string[]) {
 export async function createDirectories(...directoryPaths: string[]) {
   return Promise.all(directoryPaths.map((directoryPath) => mkdir(directoryPath, { recursive: true })));
 }
+
+export function getExtensionUri() {
+  return Controller.instance.context.extensionUri;
+}
diff --git a/deadlock-plugins/deadlock-extension/src/view/CommandTree.ts b/deadlock-plugins/deadlock-extension/src/view/CommandTree.ts
index 8fdfd7b7e4ccc096b1df28430c1d2e452c5b4c44..9c62aacdd0fb13b7918643cd38e77c0ce14a8e14 100644
--- a/deadlock-plugins/deadlock-extension/src/view/CommandTree.ts
+++ b/deadlock-plugins/deadlock-extension/src/view/CommandTree.ts
@@ -1,12 +1,12 @@
 import { MissionCommand, MissionHandler } from '../model/mission';
 import { commands, Event, EventEmitter, ThemeColor, ThemeIcon, TreeDataProvider, TreeItem, window } from 'vscode';
-import Recorder from '../recorder/recorder';
 import { MISSION_PATH_IC } from '../core/config';
 import { ChildProcessWithoutNullStreams, spawn } from 'child_process';
 import AttemptBuilder from '../model/attempt';
 import ApiService from '../core/api.service';
 import UserMission from '../core/mission/model/userMission';
 import { pushOnCommitQueueIfNotReviewing } from '../recorder/utils/gitea';
+import GitMission from '../core/gitMission';
 
 export class CommandTreeProvider implements TreeDataProvider<CommandItem> {
   getTreeItem(element: CommandItem): TreeItem {
@@ -103,10 +103,10 @@ class CommandItem extends TreeItem {
     const output = window.createOutputChannel(`${outputPrefix} - ${this.missionCommand.name}`);
     output.show();
     const attempt = new AttemptBuilder(
-      (await ApiService.getInstance().getCurrentUser()).id,
-      UserMission.getInstance().missionId,
+      (await ApiService.instance.getCurrentUser()).id,
+      UserMission.instance.missionId,
       this.missionCommand.type === 'submit',
-      UserMission.getInstance().storyId,
+      UserMission.instance.storyId,
     );
     this.spawnHandler = spawn(this.parced.cmd, this.parced.args, {
       cwd: MISSION_PATH_IC,
@@ -123,8 +123,8 @@ class CommandItem extends TreeItem {
       output.appendLine(`${outputPrefix} - ${this.missionCommand.name} - exited with code ${code}`);
       attempt.setExitCode(code ?? undefined);
       if (this.missionCommand.type === 'submit' || this.missionCommand.type === 'run') {
-        pushOnCommitQueueIfNotReviewing(Recorder.instance.gitMission, 'Run', async (commit) => {
-          await ApiService.getInstance().submitAttempt(attempt.build(commit?.commit));
+        pushOnCommitQueueIfNotReviewing(GitMission.instance, 'Run', async (commit) => {
+          await ApiService.instance.submitAttempt(attempt.build(commit?.commit));
         });
       }
       this.isRunning = false;
diff --git a/deadlock-plugins/deadlock-extension/src/view/briefingView.ts b/deadlock-plugins/deadlock-extension/src/view/briefingView.ts
index ae6dfaf5a7f4b25dd89388998e0831c778a18274..71db47c9617ece2ea80bbbf8f9ec7136b3c95ba5 100644
--- a/deadlock-plugins/deadlock-extension/src/view/briefingView.ts
+++ b/deadlock-plugins/deadlock-extension/src/view/briefingView.ts
@@ -69,10 +69,10 @@ export default class BriefingView extends WebviewBase {
   async render() {
     let output = '';
 
-    const missionUser = UserMission.getInstance();
+    const missionUser = UserMission.instance;
 
     if (missionUser.isReviewing()) {
-      const user = await ApiService.getInstance().getCurrentUser();
+      const user = await ApiService.instance.getCurrentUser();
       const giteaUser = await missionUser.getGiteaUser();
       output += `
         <h2>Professeur</h2>
diff --git a/deadlock-plugins/deadlock-extension/src/view/quickSetupView.ts b/deadlock-plugins/deadlock-extension/src/view/quickSetupView.ts
index 0c3ec6a80c8760db1e4c03eca115fbbe5bc07c81..0f0d4f31d0f07e201999d7198cca20fa308cc354 100644
--- a/deadlock-plugins/deadlock-extension/src/view/quickSetupView.ts
+++ b/deadlock-plugins/deadlock-extension/src/view/quickSetupView.ts
@@ -1,21 +1,16 @@
-import { commands, Uri } from 'vscode';
-import { authenticateCommand, disconnectCommand } from '../core/commandHandler';
+import { commands } from 'vscode';
+import { CommandHandler } from '../core/commandHandler';
 import { openQuickSetupCommand } from '../core/controller';
-import ExtensionStore from '../core/extensionStore';
 import { extensionLog as log } from '../recorder/utils/log';
 import { WebviewBase } from './webviewBase';
 
 export const quickSetupId = 'quickSetup';
 
 export default class QuickSetupView extends WebviewBase {
-  private extensionUri: Uri;
-  private extensionStore: ExtensionStore;
   private _isAlreadyConnected: boolean;
 
-  constructor(extensionUri: Uri) {
+  constructor() {
     super(quickSetupId, 'QuickSetup', openQuickSetupCommand);
-    this.extensionUri = extensionUri;
-    this.extensionStore = ExtensionStore.getInstance();
     this._isAlreadyConnected = false;
   }
 
@@ -87,7 +82,7 @@ export default class QuickSetupView extends WebviewBase {
   }
 
   renderHeaderHtml() {
-    const toolkitUri = this.getExternalRessourcePath(this.extensionUri, [
+    const toolkitUri = this.getExternalRessourcePath([
       'node_modules',
       '@vscode',
       'webview-ui-toolkit',
@@ -95,13 +90,9 @@ export default class QuickSetupView extends WebviewBase {
       'toolkit.js',
     ]);
 
-    const customStyle = this.getExternalRessourcePath(this.extensionUri, [
-      'resources',
-      'styles',
-      'gettingStartedView.css',
-    ]);
+    const customStyle = this.getExternalRessourcePath(['resources', 'styles', 'gettingStartedView.css']);
 
-    const customScript = this.getExternalRessourcePath(this.extensionUri, ['resources', 'js', 'gettingStartedView.js']);
+    const customScript = this.getExternalRessourcePath(['resources', 'js', 'gettingStartedView.js']);
 
     return `
          <meta charset="UTF-8">
@@ -114,10 +105,10 @@ export default class QuickSetupView extends WebviewBase {
   onMessageReceive(message: any): void {
     switch (message.command) {
       case 'openAuthenticationPageAction':
-        commands.executeCommand(authenticateCommand.command);
+        commands.executeCommand(CommandHandler.instance.authenticateCommand.command);
         return;
       case 'disconnectUserAction':
-        commands.executeCommand(disconnectCommand.command);
+        commands.executeCommand(CommandHandler.instance.disconnectCommand.command);
         return;
     }
   }
diff --git a/deadlock-plugins/deadlock-extension/src/view/startedMissionsView.ts b/deadlock-plugins/deadlock-extension/src/view/startedMissionsView.ts
index 8fac6e7ee6e1bb1504b4980c0cdd47bec1447ed9..dda4a28edbedd42f61f15f8d1c9b1aebe54da196 100644
--- a/deadlock-plugins/deadlock-extension/src/view/startedMissionsView.ts
+++ b/deadlock-plugins/deadlock-extension/src/view/startedMissionsView.ts
@@ -1,23 +1,18 @@
 import { randomBytes } from 'crypto';
 import { existsSync, readdirSync, readFileSync } from 'fs';
 import { join } from 'path';
-import { ExtensionContext, Webview, WebviewView, WebviewViewProvider } from 'vscode';
+import { Webview, WebviewView, WebviewViewProvider } from 'vscode';
 import Controller from '../core/controller';
 import { extensionWarn } from '../recorder/utils/log';
 import { getUri } from './webviewBase';
 import { missionWorkdir } from '../core/config';
 import UserMission from '../core/mission/model/userMission';
+import { getExtensionUri } from '../recorder/utils/workdir';
 export default class StartedMissionsView implements WebviewViewProvider {
-  private readonly controller: Controller;
-  constructor(private context: ExtensionContext) {
-    this.controller = Controller.getInstance(context);
-  }
-
   resolveWebviewView(webviewView: WebviewView): void | Thenable<void> {
     webviewView.webview.options = {
       enableScripts: true,
-
-      localResourceRoots: [this.context.extensionUri],
+      localResourceRoots: [getExtensionUri()],
     };
     webviewView.webview.html = this._getHtmlForWebview(webviewView.webview);
     webviewView.webview.onDidReceiveMessage(this.onMessageReceive.bind(this));
@@ -28,7 +23,7 @@ export default class StartedMissionsView implements WebviewViewProvider {
       case 'openMission': {
         const path = join(missionWorkdir, message.mission, '.config', 'user-challenge.json');
         const userMission: UserMission = JSON.parse(readFileSync(path, 'utf8'));
-        Controller.getInstance().launchMission({
+        Controller.instance.launchMission({
           missionId: userMission.missionId,
           missionVersion: userMission.missionVersion,
           storyId: userMission.storyId,
@@ -39,17 +34,11 @@ export default class StartedMissionsView implements WebviewViewProvider {
   }
 
   private _getHtmlForWebview(webview: Webview) {
-    const toolkitUri = getUri(webview, this.context.extensionUri, [
-      'node_modules',
-      '@vscode',
-      'webview-ui-toolkit',
-      'dist',
-      'toolkit.js',
-    ]);
+    const toolkitUri = getUri(webview, ['node_modules', '@vscode', 'webview-ui-toolkit', 'dist', 'toolkit.js']);
 
-    const css = getUri(webview, this.context.extensionUri, ['resources', 'styles', 'startedMissionsView.css']);
+    const css = getUri(webview, ['resources', 'styles', 'startedMissionsView.css']);
 
-    const js = getUri(webview, this.context.extensionUri, ['resources', 'js', 'startedMissionsView.js']);
+    const js = getUri(webview, ['resources', 'js', 'startedMissionsView.js']);
 
     // find all folders in mission directory
     let missionsHtml = '';
diff --git a/deadlock-plugins/deadlock-extension/src/view/webviewBase.ts b/deadlock-plugins/deadlock-extension/src/view/webviewBase.ts
index a2a62417a14fafdf86c917acca48502ea06bd0e4..821b96ddd1be98254b3f4d8a40234431f393c4e3 100644
--- a/deadlock-plugins/deadlock-extension/src/view/webviewBase.ts
+++ b/deadlock-plugins/deadlock-extension/src/view/webviewBase.ts
@@ -1,4 +1,3 @@
-'use strict';
 import {
   Command,
   commands,
@@ -10,6 +9,7 @@ import {
   WebviewPanelOnDidChangeViewStateEvent,
   window,
 } from 'vscode';
+import { getExtensionUri } from '../recorder/utils/workdir';
 
 const emptyCommands: Disposable[] = [
   {
@@ -19,8 +19,8 @@ const emptyCommands: Disposable[] = [
   },
 ];
 
-export function getUri(webview: Webview, extensionUri: Uri, pathList: string[]) {
-  return webview.asWebviewUri(Uri.joinPath(extensionUri, ...pathList));
+export function getUri(webview: Webview, pathList: string[]) {
+  return webview.asWebviewUri(Uri.joinPath(getExtensionUri(), ...pathList));
 }
 
 export abstract class WebviewBase implements Disposable {
@@ -33,8 +33,8 @@ export abstract class WebviewBase implements Disposable {
     this.load();
   }
 
-  getExternalRessourcePath(extensionUri: Uri, pathList: string[]) {
-    return getUri(this.panel!.webview, extensionUri, pathList);
+  getExternalRessourcePath(pathList: string[]) {
+    return getUri(this.panel!.webview, pathList);
   }
 
   registerCommands(): Disposable[] {